From d6b0f5e9b84ab3cbaf2800252e9c5ac7c7c6d782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 18 Dec 2023 18:15:31 +0100 Subject: [PATCH 001/192] added some docstrings to the BAL submodule --- apax/bal/api.py | 57 +++++++++++++++++++++++++++++--- apax/bal/feature_maps.py | 21 +++++++++--- apax/bal/selection.py | 7 ++++ apax/bal/transforms.py | 13 ++++++-- examples/01_Model_Training.ipynb | 0 5 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 examples/01_Model_Training.ipynb diff --git a/apax/bal/api.py b/apax/bal/api.py index b4eecae1..e9babce3 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -6,6 +6,7 @@ from ase import Atoms from click import Path from tqdm import trange +from flax.core.frozen_dict import FrozenDict from apax.bal import feature_maps, kernel, selection, transforms from apax.data.initialization import RawDataset @@ -22,8 +23,8 @@ def create_feature_fn( model: EnergyModel, - params, - base_feature_map, + params: FrozenDict, + base_feature_map: feature_maps.FeatureTransformation, feature_transforms=[], is_ensemble: bool = False, ): @@ -33,6 +34,21 @@ def create_feature_fn( All transformations are applied on the feature function, not on computed features. Only the final function is jit compiled. + + + Attributes + ---------- + model: EnergyModel + Model to be transformed. + params: FrozenDict + Model parameters + base_feature_map: FeatureTransformation + Class that transforms the model into a `FeatureMap` + feature_transforms: list + Feature tranforms to be applied on top of the base feature map transform. + Examples would include multiplcation with or addition of a constant. + is_ensemble: bool + Whether or not to apply the ensemble transformation i.e. an averaging of kernels for model ensembles. """ feature_fn = base_feature_map.apply(model) @@ -48,8 +64,16 @@ def create_feature_fn( return feature_fn -def compute_features(feature_fn, dataset: AtomisticDataset): - """Compute the features of a dataset.""" +def compute_features(feature_fn: feature_maps.FeatureMap, dataset: AtomisticDataset) -> np.ndarray: + """Compute the features of a dataset. + + Attributes + ---------- + feature_fn: FeatureMap + Function to compute the features with. + dataset: AtomisticDataset + Dataset to compute the features for. + """ features = [] n_data = dataset.n_data ds = dataset.batch() @@ -74,7 +98,30 @@ def kernel_selection( feature_transforms: list = [], selection_batch_size: int = 10, processing_batch_size: int = 64, -): +) -> list[int]: + """ + Main fuinction to facilitate batch data selection. + Currently only the last layer gradient features and MaxDist selection method are available. + More can be added as needed as this function is agnostic of the feature map/selection method internals. + + Attributes + ---------- + model_dir: Union[Path, List[Path]] + Path to the trained model or models which should be used to compute features. + train_atoms: List[Atoms] + List of `ase.Atoms` used to train the models. + pool_atoms: List[Atoms] + List of `ase.Atoms` to select new data from. + base_fm_options: + Dict + selection_method: + feature_transforms: + selection_batch_size: + Amount of new data points to be selected from `pool_atoms`. + processing_batch_size: + Amount of data points to compute the features for at once. + Does not effect results, just the speed of processing. + """ selection_fn = { "max_dist": selection.max_dist_selection, }[selection_method] diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index 1bfa62b6..264b0436 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -1,10 +1,21 @@ -from typing import Literal, Tuple, Union +from typing import Callable, Literal, Tuple, Union import jax import jax.numpy as jnp from flax.traverse_util import flatten_dict, unflatten_dict from pydantic import BaseModel, TypeAdapter +from apax.model.gmnn import EnergyModel +from flax.core.frozen_dict import FrozenDict + + +FeatureMap = Callable[[FrozenDict, dict], jax.Array] + +class FeatureTransformation(BaseModel): + + def apply(self, model: EnergyModel) -> FeatureMap: + ... + def extract_feature_params(params: dict, layer_name: str) -> Tuple[dict, dict]: """Separate params into those belonging to a selected layer @@ -22,7 +33,7 @@ def extract_feature_params(params: dict, layer_name: str) -> Tuple[dict, dict]: return feature_layer_params, remaining_params -class LastLayerGradientFeatures(BaseModel, extra="forbid"): +class LastLayerGradientFeatures(FeatureTransformation, extra="forbid"): """ Model transfomration which computes the gradient of the output wrt. the specified layer. @@ -32,7 +43,7 @@ class LastLayerGradientFeatures(BaseModel, extra="forbid"): name: Literal["ll_grad"] layer_name: str = "dense_2" - def apply(self, model): + def apply(self, model: EnergyModel) -> FeatureMap: def ll_grad(params, inputs): ll_params, remaining_params = extract_feature_params(params, self.layer_name) @@ -67,12 +78,12 @@ def inner(ll_params): return ll_grad -class IdentityFeatures(BaseModel, extra="forbid"): +class IdentityFeatures(FeatureTransformation, extra="forbid"): """Identity feature map. For debugging purposes""" name: Literal["identity"] - def apply(self, model): + def apply(self, model: EnergyModel) -> FeatureMap: return model.apply diff --git a/apax/bal/selection.py b/apax/bal/selection.py index 2d21c354..d90487e1 100644 --- a/apax/bal/selection.py +++ b/apax/bal/selection.py @@ -11,6 +11,13 @@ def max_dist_selection(matrix: KernelMatrix, batch_size: int): https://arxiv.org/pdf/2203.09410.pdf https://doi.org/10.1039/D2DD00034B + + Attributes + ---------- + matrix: KernelMatrix + Kernel used to compare structures. + batch_size: int + Number of new data points to be selected. """ n_train = matrix.n_train diff --git a/apax/bal/transforms.py b/apax/bal/transforms.py index 344752d3..5e8eca83 100644 --- a/apax/bal/transforms.py +++ b/apax/bal/transforms.py @@ -1,8 +1,13 @@ import jax import jax.numpy as jnp +from apax.bal.feature_maps import FeatureMap -def ensemble_features(feature_fn): + +def ensemble_features(feature_fn: FeatureMap) -> FeatureMap: + """ + Feature map transformation which averages the kernels of a model ensemble. + """ ensemble_feature_fn = jax.vmap(feature_fn, (0, None), 0) def averaged_feature_fn(params, x): @@ -24,6 +29,10 @@ def averaged_feature_fn(params, x): return averaged_feature_fn -def batch_features(feature_fn): +def batch_features(feature_fn: FeatureMap) -> FeatureMap: + """ + Vectorizes a feature map over structures. + Should be the last transformation applied to a feature map. + """ batched_feature_fn = jax.vmap(feature_fn, (None, 0), 0) return batched_feature_fn diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb new file mode 100644 index 00000000..e69de29b From 7a41ac68922084ee40b9e961be9149eaeb9fe298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 22 Dec 2023 20:21:51 +0100 Subject: [PATCH 002/192] Moved existing examples over to jupyter notebooks --- .../_tutorials/01_Model_Training.nblink | 3 + .../_tutorials/02_Molecular_dynamics.nblink | 3 + .../_tutorials/03_Transfer_Learning.nblink | 3 + .../_tutorials/04_Batch_Data_Selection.nblink | 3 + docs/source/_tutorials/index.rst | 2 +- docs/source/_tutorials/md_with_ase.rst | 10 -- docs/source/_tutorials/molecular_dynamics.rst | 62 ------- docs/source/_tutorials/training_a_model.rst | 79 --------- docs/source/_tutorials/transfer_learning.rst | 23 --- examples/01_Model_Training.ipynb | 162 ++++++++++++++++++ examples/02_Molecular_Dynamics.ipynb | 116 +++++++++++++ examples/03_Transfer_learning.ipynb | 19 ++ examples/04_Batch_Data_Selection.ipynb | 0 13 files changed, 310 insertions(+), 175 deletions(-) create mode 100644 docs/source/_tutorials/01_Model_Training.nblink create mode 100644 docs/source/_tutorials/02_Molecular_dynamics.nblink create mode 100644 docs/source/_tutorials/03_Transfer_Learning.nblink create mode 100644 docs/source/_tutorials/04_Batch_Data_Selection.nblink delete mode 100644 docs/source/_tutorials/md_with_ase.rst delete mode 100644 docs/source/_tutorials/molecular_dynamics.rst delete mode 100644 docs/source/_tutorials/training_a_model.rst delete mode 100644 docs/source/_tutorials/transfer_learning.rst create mode 100644 examples/02_Molecular_Dynamics.ipynb create mode 100644 examples/03_Transfer_learning.ipynb create mode 100644 examples/04_Batch_Data_Selection.ipynb diff --git a/docs/source/_tutorials/01_Model_Training.nblink b/docs/source/_tutorials/01_Model_Training.nblink new file mode 100644 index 00000000..ff4c4579 --- /dev/null +++ b/docs/source/_tutorials/01_Model_Training.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/01_Model_Training.ipynb" +} \ No newline at end of file diff --git a/docs/source/_tutorials/02_Molecular_dynamics.nblink b/docs/source/_tutorials/02_Molecular_dynamics.nblink new file mode 100644 index 00000000..4dfadfe9 --- /dev/null +++ b/docs/source/_tutorials/02_Molecular_dynamics.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/02_Molecular_Dynamics.ipynb" +} \ No newline at end of file diff --git a/docs/source/_tutorials/03_Transfer_Learning.nblink b/docs/source/_tutorials/03_Transfer_Learning.nblink new file mode 100644 index 00000000..27f929dc --- /dev/null +++ b/docs/source/_tutorials/03_Transfer_Learning.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/03_Transfer_Learning.ipynb" +} \ No newline at end of file diff --git a/docs/source/_tutorials/04_Batch_Data_Selection.nblink b/docs/source/_tutorials/04_Batch_Data_Selection.nblink new file mode 100644 index 00000000..dbd195e4 --- /dev/null +++ b/docs/source/_tutorials/04_Batch_Data_Selection.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/04_Batch_Data_Selection.ipynb" +} \ No newline at end of file diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index e1f70191..8df2115c 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -4,7 +4,7 @@ Tutorials .. toctree:: :maxdepth: 2 + 01_Model_Training md_with_ase molecular_dynamics - training_a_model transfer_learning diff --git a/docs/source/_tutorials/md_with_ase.rst b/docs/source/_tutorials/md_with_ase.rst deleted file mode 100644 index 50b69f9f..00000000 --- a/docs/source/_tutorials/md_with_ase.rst +++ /dev/null @@ -1,10 +0,0 @@ -The ASE calculator -================== - -If you require some ASE features during your simulation, we provide an alternative to the JaxMD interface. - -An ASE calculator of a trained model can be instantiated as follows - -CODE - -Please refer to the ASE documentation LINK to see how to use ASE calculators. \ No newline at end of file diff --git a/docs/source/_tutorials/molecular_dynamics.rst b/docs/source/_tutorials/molecular_dynamics.rst deleted file mode 100644 index ecaa3231..00000000 --- a/docs/source/_tutorials/molecular_dynamics.rst +++ /dev/null @@ -1,62 +0,0 @@ -Molecular Dynamics with JaxMD -============================= - - -JaxMD LINK is a high performance molecular dynamics engine built on top of Jax LINK. -Out of the boy, apax ships with a simple simulation loop using the Nose-Hoover-Chain thermostat implemented in JaxMD. -Note that this tutorial assumes that you have a trained model at hand. -See the previous tutorial LINK for further information. - -## Configuration -We can once again use the template command to give ourselves a quickstart. - -`apax template md --minimal` - -Open the config and specify the starting structure and simulation parameters. -If you specify the data set file itself, the first structure of the data set is going to be used as the initial structure. -Your `md_config_minimal.yaml` should look similar to this: - -```yaml -duration: 20_000 # fs -initial_structure: md17.extxyz -``` - -As with training configurations, we can use the `validate` command to ensure our input is valid before we submit the calculation. - -## Running the simulation - -The simulation can be started by running - -`apax md config.yaml md_config_minimal.yaml` - -where `config.yaml` is the configuration file that was used to train the model. - -During the simulation, a progress bar tracks the instantaneous temperature at each outer step. - -`prog bar` - -## Calculating Vibrational Spectra - -The trajectory calculated above can be used to obtain physical observables. -For this tutorial, we are going to compute an anharmonic vibrational spectrum for benzene. -Note that the code below is intended simply demonstration purposes and more sophisticated trajectory analysis tools should be used in production simulations. - -```python -# analysis.py: -... -``` - -PIC - -Congratulations, you have calculated the first observable from a trajectory generated with apax and jaxMD! - - - -## Custom Simulation Loops - -More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). -Trained apax models can of course be used as `energy_fn` in such custom simulations. -If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on Github LINK. - - - diff --git a/docs/source/_tutorials/training_a_model.rst b/docs/source/_tutorials/training_a_model.rst deleted file mode 100644 index f5edf02c..00000000 --- a/docs/source/_tutorials/training_a_model.rst +++ /dev/null @@ -1,79 +0,0 @@ -Training -======== - -## Acquiring a dataset - -In this tutorial we are going to train a model from scratch on a molecular dataset from the MD17 collection. -Start by creating a project folder and downloading the dataset. - -mkdir project -cd project - -You can obtain the benzene dataset either by running the following command or manually from this website. - -curl ... ... - -apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). - - -## Configuration files - -Next, we require a configuration file that specifies the model and training parameters. -In order to get users quickly up and running, our command line interface provides an easy way to generate input templates. -The provided templates come in in two levels of verbosity: minimal and full. -In the following we are going to use a minimal input file. To see a complete list and explanation of all parameters, consult the documentation page LINK. -For more information on the CLI, simply run `apax -h`. - -apax template train --minimal - -Open the resulting `config_minimal.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded. -For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. - -The filled in configuration file should look similar to this one. - -```yaml -data: - data_path: md17.extexyz - epochs: 1000 - n_train: 1000 - .... -``` - -In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster. - -`apax validate train config_minimal.yaml` - -Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file. -For example, changing `epochs` to `-1000`, validate will give the following feedback to the user: - -`PYDANTIC ERROR` - -## Training - -Model training can be started by running - -`apax train config.yaml` - -During training, apax displays a progress bar to keep track of the validation loss. -This progress bar is optional however and can be turned off in the config. LINK -The default configuration writes training metrics to a CSV file, but TensorBoard is also supported. -One can specify which to use by adding the following section to the input file: - -```yaml -callbacks: - - CSV -``` - -If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint. - -Evaluation -========== - -After the training is completed and we are satisfied with our choice of hyperparameters and vadliation loss, we can evaluate the model on the test set. -We provide a separate command for test set evaluation: - -`apax evaluate config_minimal.yaml` - -TODO pretty print results to the terminal - -Congratulations, you have successfully trained and evaluated your fitrst apax model! \ No newline at end of file diff --git a/docs/source/_tutorials/transfer_learning.rst b/docs/source/_tutorials/transfer_learning.rst deleted file mode 100644 index b70a2f02..00000000 --- a/docs/source/_tutorials/transfer_learning.rst +++ /dev/null @@ -1,23 +0,0 @@ -Transfer Learning -================= - -apax comes with discriminative transfer learning capabilities out of the box. -In this tutorial we are going to fine tune a model trained on benzene data at the DFT level of theory to CCSDT. - -First download the appropriate dataset from the sgdml website. - - -Transfer learning can be facilitated in apax by adding the path to a pre-trained model in the config. -Furthermore, we can freeze or reduce the learning rate of various components by adjusting the `optimizer` section of the config. - -```yaml -optimizer: - nn_lr: 0.004 - embedding_lr: 0.0 -``` - -Learning rates of 0.0 will mask the respective weights during training steps. -Here, we will freeze the descriptor, reinitialize the scaling and shifting parameters and reduce the learning rate of all other components. - -We can now fine tune the model by running -`apax train config.yaml` diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index e69de29b..dd60fa86 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Model Training\n", + "\n", + "In this tutorial we are going to train a model from scratch on a molecular dataset from the MD17 collection.\n", + "Start by creating a project folder and downloading the dataset.\n", + "\n", + "## Acquiring a dataset\n", + "\n", + "# TODO tmpdir\n", + "\n", + "```bash\n", + "mkdir project\n", + "cd project\n", + "```\n", + "You can obtain the benzene dataset either by running the following command or manually from this website.\n", + "\n", + "`curl ... ...`\n", + "\n", + "apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TODO Dataset splitting" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configuration files\n", + "\n", + "Next, we require a configuration file that specifies the model and training parameters.\n", + "In order to get users quickly up and running, our command line interface provides an easy way to generate input templates.\n", + "The provided templates come in in two levels of verbosity: minimal and full.\n", + "In the following we are going to use a minimal input file. To see a complete list and explanation of all parameters, consult the documentation page LINK.\n", + "For more information on the CLI, simply run `apax -h`.\n", + "\n", + "apax template train --minimal\n", + "\n", + "Open the resulting `config_minimal.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", + "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training.\n", + "\n", + "The filled in configuration file should look similar to this one.\n", + "\n", + "```yaml\n", + "data:\n", + " data_path: md17.extexyz\n", + " epochs: 1000\n", + " n_train: 1000\n", + " ....\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n", + "\n", + "`apax validate train config_minimal.yaml`\n", + "\n", + "Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file.\n", + "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:\n", + "\n", + "`PYDANTIC ERROR`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training\n", + "\n", + "Model training can be started by running\n", + "\n", + "`apax train config.yaml`\n", + "\n", + "During training, apax displays a progress bar to keep track of the validation loss.\n", + "This progress bar is optional however and can be turned off in the config. LINK\n", + "The default configuration writes training metrics to a CSV file, but TensorBoard is also supported.\n", + "One can specify which to use by adding the following section to the input file:\n", + "\n", + "```yaml\n", + "callbacks:\n", + " - CSV\n", + "```\n", + "\n", + "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TODO plot train val loss" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports\n", + "\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluation\n", + "==========\n", + "\n", + "After the training is completed and we are satisfied with our choice of hyperparameters and vadliation loss, we can evaluate the model on the test set.\n", + "We provide a separate command for test set evaluation:\n", + "\n", + "`apax evaluate config_minimal.yaml`\n", + "\n", + "TODO pretty print results to the terminal\n", + "\n", + "Congratulations, you have successfully trained and evaluated your first apax model!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A Closer Look At Training Parameters\n", + "\n", + "TODO" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "apax311", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb new file mode 100644 index 00000000..1264c277 --- /dev/null +++ b/examples/02_Molecular_Dynamics.ipynb @@ -0,0 +1,116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Molecular Dynamics\n", + "\n", + "In this tutorial we will cover how to use trained models to drive MD simulations.\n", + "For this purpose, apax offers two options: ASE and JaxMD.\n", + "Both will be covered below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Model Training\n", + "\n", + "First we need to train a model.\n", + "If you have the parameters from tutorial 01, you can point the paths to those models and skip the current section." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The ASE calculator\n", + "\n", + "If you require some ASE features during your simulation, we provide an alternative to the JaxMD interface.\n", + "\n", + "An ASE calculator of a trained model can be instantiated as follows\n", + "\n", + "CODE\n", + "\n", + "Please refer to the ASE documentation LINK to see how to use ASE calculators." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## JaxMD\n", + "\n", + "While the ASE interface is convenient and flexible, it is not meant for high performance applications.\n", + "For these purposes, apax comes with an interface to JaxMD.\n", + "JaxMD LINK is a high performance molecular dynamics engine built on top of Jax LINK.\n", + "The CLI provides easy access to standard NVT and NPT simulations.\n", + "More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). \n", + "Trained apax models can of course be used as `energy_fn` in such custom simulations.\n", + "If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on Github LINK.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Configuration\n", + "We can once again use the template command to give ourselves a quickstart.\n", + "\n", + "`apax template md --minimal`\n", + "\n", + "Open the config and specify the starting structure and simulation parameters.\n", + "If you specify the data set file itself, the first structure of the data set is going to be used as the initial structure.\n", + "Your `md_config_minimal.yaml` should look similar to this:\n", + "\n", + "```yaml\n", + "duration: 20_000 # fs\n", + "initial_structure: md17.extxyz\n", + "```\n", + "\n", + "As with training configurations, we can use the `validate` command to ensure our input is valid before we submit the calculation.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running the simulation\n", + "\n", + "The simulation can be started by running\n", + "\n", + "`apax md config.yaml md_config_minimal.yaml`\n", + "\n", + "where `config.yaml` is the configuration file that was used to train the model.\n", + "\n", + "During the simulation, a progress bar tracks the instantaneous temperature at each outer step.\n", + "\n", + "`prog bar`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Observables\n", + "\n", + "TODO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/03_Transfer_learning.ipynb b/examples/03_Transfer_learning.ipynb new file mode 100644 index 00000000..c64720b2 --- /dev/null +++ b/examples/03_Transfer_learning.ipynb @@ -0,0 +1,19 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Transfer Learning\n", + "\n" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/04_Batch_Data_Selection.ipynb b/examples/04_Batch_Data_Selection.ipynb new file mode 100644 index 00000000..e69de29b From cb9a5e54b03ec592a87554e68c28ca73fe9e0ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 22 Dec 2023 20:22:14 +0100 Subject: [PATCH 003/192] added docstring to ASE calculator --- apax/md/ase_calc.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 63a1dc97..decdad56 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -90,6 +90,11 @@ def ensemble(positions, Z, idx, box, offsets): class ASECalculator(Calculator): """ ASE Calculator for apax models. + Always implements energy and force predictions. + Stress predictions and corresponding uncertainties are added to + `implemented_properties` based on whether the stress flag is set + in the model config and whether a model ensemble is loaded. + """ implemented_properties = [ @@ -105,6 +110,21 @@ def __init__( padding_factor: float = 1.5, **kwargs ): + """ + Parameters + ---------- + model_dir: + Path to a model directory of the form `.../directory/experiment` (see Config docs for details). + If a list of model paths is provided, they will be ensembled. + dr_threshold: + Neighborlist skin for the JaxMD neighborlist. + transformations: + Function transformations applied on top of the EnergyDerivativeModel. + Transfomrations are implemented under `apax.md.transformations`. + padding_factor: + Multiple of the fallback Matscipy NL's amount of neighbors. + This NL will be padded to `len(neighbors) * padding_factor` on NL initialization. + """ Calculator.__init__(self, **kwargs) self.dr_threshold = dr_threshold self.transformations = transformations From d58939f00c21d24e21f86f32f709d8844a6b6d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 22 Dec 2023 20:22:49 +0100 Subject: [PATCH 004/192] added transfer learning description --- examples/03_Transfer_learning.ipynb | 40 ++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/examples/03_Transfer_learning.ipynb b/examples/03_Transfer_learning.ipynb index c64720b2..7d3cc3a2 100644 --- a/examples/03_Transfer_learning.ipynb +++ b/examples/03_Transfer_learning.ipynb @@ -5,7 +5,45 @@ "metadata": {}, "source": [ "# Transfer Learning\n", - "\n" + "\n", + "Datasets computed at high levels of theory are expensive and thus, usually small. \n", + "A model trained on this data might not be able to generalize well to unseen configurations.\n", + "Some times this can be remedied with transfer learning:\n", + "By first training a model on a lot of data from a less expensive level of theory, only small adjustments to the parameters are required to accurately reproduce the potential energy surface of a different level of theory.\n", + "\n", + "\n", + "Alternatively, the level of theory might not change, but the dataset is extended.\n", + "This is the case in learning on the fly scenarios.\n", + "For a demonstration of using transfer learning for learning on the fly, see the corresponding example from the IPSuite documentation LINK.\n", + "\n", + "\n", + "apax comes with discriminative transfer learning capabilities out of the box.\n", + "In this tutorial we are going to fine tune a model trained on benzene data at the DFT level of theory to CCSDT." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "First download the appropriate dataset from the sgdml website.\n", + "\n", + "\n", + "Transfer learning can be facilitated in apax by adding the path to a pre-trained model in the config.\n", + "Furthermore, we can freeze or reduce the learning rate of various components by adjusting the `optimizer` section of the config.\n", + "\n", + "```yaml\n", + "optimizer:\n", + " nn_lr: 0.004\n", + " embedding_lr: 0.0\n", + "```\n", + "\n", + "Learning rates of 0.0 will mask the respective weights during training steps.\n", + "Here, we will freeze the descriptor, reinitialize the scaling and shifting parameters and reduce the learning rate of all other components.\n", + "\n", + "We can now fine tune the model by running\n", + "`apax train config.yaml`" ] } ], From ce05d97656edf1ec49d1b2ee5d371a4454f54910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 22 Dec 2023 20:23:46 +0100 Subject: [PATCH 005/192] added batch data selection description --- examples/04_Batch_Data_Selection.ipynb | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/examples/04_Batch_Data_Selection.ipynb b/examples/04_Batch_Data_Selection.ipynb index e69de29b..9ca270be 100644 --- a/examples/04_Batch_Data_Selection.ipynb +++ b/examples/04_Batch_Data_Selection.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Batch Active Learning\n", + "\n", + "While it is possible to perform rudimentary data selection simply by randomly choosing samples, the batch of data thus drawn might not be the most informative one.\n", + "Choosing those samples whith the largest prediction uncertainties from trajectories often results in the selection of configurations from subsequent time steps.\n", + "\n", + "Batch selection methods can be constructed to select informative and diverse data, with or without following the underlying distribution.\n", + "\n", + "We will illustrate this in a mock learning on the fly setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO Model Training\n", + "# TODO run MD\n", + "# TODO illustrate selection vs max uncertainty" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From a37d4d102236db6e4d7d923ef06114a979e31f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Sat, 20 Jan 2024 17:21:34 +0100 Subject: [PATCH 006/192] sketch of batch eval --- apax/md/ase_calc.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 6422b5a5..a90d8f51 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -8,6 +8,8 @@ from ase.calculators.calculator import Calculator, all_changes from jax_md import partition, quantity, space from matscipy.neighbours import neighbour_list +from tqdm import trange +from apax.data.initialization import RawDataset, initialize_dataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters @@ -127,6 +129,7 @@ def __init__( self.neighbor_fn = None self.neighbors = None self.offsets = None + self.model = None def initialize(self, atoms): box = jnp.asarray(atoms.cell.array, dtype=jnp.float64) @@ -146,6 +149,7 @@ def initialize(self, atoms): for transformation in self.transformations: model = transformation.apply(model, self.n_models) + self.model = model self.step = get_step_fn(model, atoms, self.neigbor_from_jax) self.neighbor_fn = neighbor_fn @@ -215,6 +219,31 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): self.results = {k: np.array(v, dtype=np.float64) for k, v in results.items()} self.results["energy"] = self.results["energy"].item() + def batch_eval(self, data, batch_size=64, silent=False): + if self.model is None: + self.initialize(data[0]) + dataset = initialize_dataset(self.model_config, RawDataset(atoms_list=data), calc_stats=False) + dataset.set_batch_size(batch_size) + + features = [] + n_data = dataset.n_data + ds = dataset.batch() + batched_model = jax.jit(jax.vmap(self.model,)) + + pbar = trange(n_data, desc="Computing features", ncols=100, leave=True, disable=silent) + for i, (inputs, _) in enumerate(ds): + results = batched_model(inputs) + unpadded_results = unpad_results(results, inputs) + for j in range(batch_size): + data[i].calc = SinglepointCalculator(atoms=data[i], results={}) + pbar.update(batch_size) + pbar.close() + + + + + + def neighbor_calculable_with_jax(box, r_max): if np.all(box < 1e-6): From 9b4cab3b9349562adf358afe6500313786cf70de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 1 Feb 2024 14:59:15 +0100 Subject: [PATCH 007/192] fixed jax nl always allocating in cartesian coords and repeated allocations --- apax/md/ase_calc.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 6422b5a5..8d7d2a65 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -150,14 +150,23 @@ def initialize(self, atoms): self.neighbor_fn = neighbor_fn if self.neigbor_from_jax: - positions = jnp.asarray(atoms.positions, dtype=jnp.float64) - self.neighbors = self.neighbor_fn.allocate(positions) + if np.any(atoms.get_cell().lengths() > 1e-6): + positions = jnp.asarray(atoms.positions, dtype=jnp.float64) + box = atoms.cell.array.T + inv_box = jnp.linalg.inv(box) + positions = space.transform(inv_box, positions) # frac coords + self.neighbors = self.neighbor_fn.allocate(positions, box=box) + else: + neighbor = neighbor.allocate(positions) + else: + idxs_i = neighbour_list("i", atoms, self.r_max) + self.padded_length = int(len(idxs_i) * self.padding_factor) def set_neighbours_and_offsets(self, atoms, box): idxs_i, idxs_j, offsets = neighbour_list("ijS", atoms, self.r_max) if len(idxs_i) > self.padded_length: - print("neighbor list overflowed, reallocating.") + print("neighbor list overflowed, extending.") self.padded_length = int(len(idxs_i) * self.padding_factor) self.initialize(atoms) @@ -178,12 +187,6 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): if self.step is None: self.initialize(atoms) - if self.neigbor_from_jax: - self.neighbors = self.neighbor_fn.allocate(positions) - else: - idxs_i = neighbour_list("i", atoms, self.r_max) - self.padded_length = int(len(idxs_i) * self.padding_factor) - elif "numbers" in system_changes: self.initialize(atoms) @@ -202,8 +205,6 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): if self.neighbors.did_buffer_overflow: print("neighbor list overflowed, reallocating.") self.initialize(atoms) - self.neighbors = self.neighbor_fn.allocate(positions) - results, self.neighbors = self.step(positions, self.neighbors, box) else: @@ -263,14 +264,11 @@ def step_fn(positions, neighbor, box): return results, neighbor else: - @jax.jit def step_fn(positions, neighbor, box, offsets): results = model(positions, Z, neighbor, box, offsets) - if "stress" in results.keys(): results = process_stress(results, box) - return results return step_fn From 63066b578fc8fa0fa271c6eaaf094a05e86b431e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:11:29 +0000 Subject: [PATCH 008/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/md/ase_calc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 8d7d2a65..5ec5f71d 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -154,7 +154,7 @@ def initialize(self, atoms): positions = jnp.asarray(atoms.positions, dtype=jnp.float64) box = atoms.cell.array.T inv_box = jnp.linalg.inv(box) - positions = space.transform(inv_box, positions) # frac coords + positions = space.transform(inv_box, positions) # frac coords self.neighbors = self.neighbor_fn.allocate(positions, box=box) else: neighbor = neighbor.allocate(positions) @@ -264,6 +264,7 @@ def step_fn(positions, neighbor, box): return results, neighbor else: + @jax.jit def step_fn(positions, neighbor, box, offsets): results = model(positions, Z, neighbor, box, offsets) From 9aefa7d20028631d7235efad987232131b1a34ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 1 Feb 2024 15:15:01 +0100 Subject: [PATCH 009/192] fixed erroneous nl allocating for gas phase systems --- apax/md/ase_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 8d7d2a65..4a528930 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -157,7 +157,7 @@ def initialize(self, atoms): positions = space.transform(inv_box, positions) # frac coords self.neighbors = self.neighbor_fn.allocate(positions, box=box) else: - neighbor = neighbor.allocate(positions) + self.neighbors = self.neighbor_fn.allocate(positions) else: idxs_i = neighbour_list("i", atoms, self.r_max) self.padded_length = int(len(idxs_i) * self.padding_factor) From 792d548e12ff7e74003439a3f44a43a46033a2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 11:09:43 +0100 Subject: [PATCH 010/192] fixed bug where positions where not initialized for gas phase systems in ASE calc --- apax/md/ase_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 3a69d2e6..48e62516 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -150,8 +150,8 @@ def initialize(self, atoms): self.neighbor_fn = neighbor_fn if self.neigbor_from_jax: + positions = jnp.asarray(atoms.positions, dtype=jnp.float64) if np.any(atoms.get_cell().lengths() > 1e-6): - positions = jnp.asarray(atoms.positions, dtype=jnp.float64) box = atoms.cell.array.T inv_box = jnp.linalg.inv(box) positions = space.transform(inv_box, positions) # frac coords From 465b96b257ec847a2aac43f3593ac3ec1b59d2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 12:55:39 +0100 Subject: [PATCH 011/192] implemented eval loop --- apax/md/ase_calc.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index cea29b6a..73eacfc6 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -6,6 +6,7 @@ import jax.numpy as jnp import numpy as np from ase.calculators.calculator import Calculator, all_changes +from ase.calculators.singlepoint import SinglePointCalculator from jax_md import partition, quantity, space from matscipy.neighbours import neighbour_list from tqdm import trange @@ -89,6 +90,18 @@ def ensemble(positions, Z, idx, box, offsets): return ensemble +def unpack_results(results, inputs): + unpacked_results = [] + + unpacked_results = jax.tree_transpose( + outer_treedef = jax.tree_structure(results), + inner_treedef = jax.tree_structure([0 for r in results["energy"]]), + pytree_to_transpose = results + ) + return unpacked_results + + + class ASECalculator(Calculator): """ ASE Calculator for apax models. @@ -226,24 +239,23 @@ def batch_eval(self, data, batch_size=64, silent=False): dataset = initialize_dataset(self.model_config, RawDataset(atoms_list=data), calc_stats=False) dataset.set_batch_size(batch_size) - features = [] + # features = [] + evaluated_data = [] n_data = dataset.n_data ds = dataset.batch() - batched_model = jax.jit(jax.vmap(self.model,)) + batched_model = jax.jit(jax.vmap(self.model, in_axes=(None, 0, 0, 0, 0, 0))) pbar = trange(n_data, desc="Computing features", ncols=100, leave=True, disable=silent) for i, (inputs, _) in enumerate(ds): results = batched_model(inputs) - unpadded_results = unpad_results(results, inputs) + unpadded_results = unpack_results(results, inputs) for j in range(batch_size): - data[i].calc = SinglepointCalculator(atoms=data[i], results={}) + atoms = data[i].copy() + atoms.calc = SinglePointCalculator(atoms=atoms, results=unpadded_results[j]) + evaluated_data.append(atoms) pbar.update(batch_size) pbar.close() - - - - - + return evaluated_data def neighbor_calculable_with_jax(box, r_max): From a57d06bf85254c91d8f37b3d43197ee9f7165dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 13:41:07 +0100 Subject: [PATCH 012/192] added uncertaintties to ASE all properties --- apax/__init__.py | 3 +++ apax/utils/helpers.py | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 apax/utils/helpers.py diff --git a/apax/__init__.py b/apax/__init__.py index 7cd23717..fd0d8918 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -4,3 +4,6 @@ os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" jax_config.update("jax_enable_x64", True) +from apax.utils.helpers import setup_ase + +setup_ase() \ No newline at end of file diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py new file mode 100644 index 00000000..0acb2378 --- /dev/null +++ b/apax/utils/helpers.py @@ -0,0 +1,9 @@ +def setup_ase(): + """Add uncertainty keys to ASE all properties. + from https://github.com/zincware/IPSuite/blob/main/ipsuite/utils/helpers.py#L10 + """ + from ase.calculators.calculator import all_properties + + for val in ["forces_uncertainty", "energy_uncertainty", "stress_uncertainty"]: + if val not in all_properties: + all_properties.append(val) From 2830b4fd2b5e1aadfa3492b41270f0ca51413856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 13:41:23 +0100 Subject: [PATCH 013/192] completed batch_eval --- apax/md/ase_calc.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index aca2e52d..0bfc4020 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -17,7 +17,7 @@ from apax.utils import jax_md_reduced -def maybe_vmap(apply, params, Z): +def maybe_vmap(apply, params): n_models = check_for_ensemble(params) if n_models > 1: @@ -54,7 +54,6 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ format=partition.Sparse, ) - Z = jnp.asarray(atomic_numbers) n_species = 119 # int(np.max(Z) + 1) builder = ModelBuilder(config.model.get_dict(), n_species=n_species) @@ -62,8 +61,7 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ apply_mask=True, init_box=np.array(box), inference_disp_fn=displacement_fn ) - energy_fn = maybe_vmap(model.apply, params, Z) - + energy_fn = maybe_vmap(model.apply, params) return energy_fn, neighbor_fn @@ -91,17 +89,17 @@ def ensemble(positions, Z, idx, box, offsets): def unpack_results(results, inputs): + n_structures = len(results["energy"]) unpacked_results = [] - - unpacked_results = jax.tree_transpose( - outer_treedef = jax.tree_structure(results), - inner_treedef = jax.tree_structure([0 for r in results["energy"]]), - pytree_to_transpose = results - ) + for i in range(n_structures): + single_results = jax.tree_map(lambda x: x[i], results) + for k,v in single_results.items(): + if "forces" in k: + single_results[k] = v[:inputs["n_atoms"][i]] + unpacked_results.append(single_results) return unpacked_results - class ASECalculator(Calculator): """ ASE Calculator for apax models. @@ -239,19 +237,25 @@ def batch_eval(self, data, batch_size=64, silent=False): dataset = initialize_dataset(self.model_config, RawDataset(atoms_list=data), calc_stats=False) dataset.set_batch_size(batch_size) - # features = [] evaluated_data = [] n_data = dataset.n_data ds = dataset.batch() - batched_model = jax.jit(jax.vmap(self.model, in_axes=(None, 0, 0, 0, 0, 0))) + batched_model = jax.jit(jax.vmap(self.model, in_axes=(0, 0, 0, 0, 0))) pbar = trange(n_data, desc="Computing features", ncols=100, leave=True, disable=silent) for i, (inputs, _) in enumerate(ds): - results = batched_model(inputs) + positions_b, Z_b, neighbor_b, box_b, offsets_b = ( + inputs["positions"], + inputs["numbers"], + inputs["idx"], + inputs["box"], + inputs["offsets"], + ) + results = batched_model(positions_b, Z_b, neighbor_b, box_b, offsets_b) unpadded_results = unpack_results(results, inputs) for j in range(batch_size): atoms = data[i].copy() - atoms.calc = SinglePointCalculator(atoms=atoms, results=unpadded_results[j]) + atoms.calc = SinglePointCalculator(atoms=atoms, **unpadded_results[j]) evaluated_data.append(atoms) pbar.update(batch_size) pbar.close() From 70aec8e7c8a550ee3c6d5191d06763d52275f092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 13:41:31 +0100 Subject: [PATCH 014/192] added h5 to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e6f51b6f..e6981eda 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ main.py tmp/ .npz .traj +.h5 events.out.* # Translations From ef616d3cf0b1bc48d94318b34c12da6bd374ba32 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:50:06 +0000 Subject: [PATCH 015/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/__init__.py b/apax/__init__.py index fd0d8918..7a2df1c3 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -6,4 +6,4 @@ jax_config.update("jax_enable_x64", True) from apax.utils.helpers import setup_ase -setup_ase() \ No newline at end of file +setup_ase() From 4a16d256f14ac380083709f1e3b73f157c80a378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 15:15:02 +0100 Subject: [PATCH 016/192] linting --- apax/data/input_pipeline.py | 14 ++++++++------ apax/md/ase_calc.py | 15 +++++++++------ apax/train/trainer.py | 10 ++++++---- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 6832c587..3e53fa33 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -134,12 +134,14 @@ def dataset_from_dicts( for key, val in labels["fixed"].items(): labels["fixed"][key] = tf.constant(val) - ds = tf.data.Dataset.from_tensor_slices(( - inputs["ragged"], - inputs["fixed"], - labels["ragged"], - labels["fixed"], - )) + ds = tf.data.Dataset.from_tensor_slices( + ( + inputs["ragged"], + inputs["fixed"], + labels["ragged"], + labels["fixed"], + ) + ) return ds diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 0bfc4020..43e1342b 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -10,8 +10,8 @@ from jax_md import partition, quantity, space from matscipy.neighbours import neighbour_list from tqdm import trange -from apax.data.initialization import RawDataset, initialize_dataset +from apax.data.initialization import RawDataset, initialize_dataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters from apax.utils import jax_md_reduced @@ -31,7 +31,6 @@ def maybe_vmap(apply, params): def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_jax): r_max = config.model.r_max - atomic_numbers = jnp.asarray(atoms.numbers) box = jnp.asarray(atoms.cell.array, dtype=jnp.float64) neigbor_from_jax = neighbor_calculable_with_jax(box, r_max) box = box.T @@ -93,9 +92,9 @@ def unpack_results(results, inputs): unpacked_results = [] for i in range(n_structures): single_results = jax.tree_map(lambda x: x[i], results) - for k,v in single_results.items(): + for k, v in single_results.items(): if "forces" in k: - single_results[k] = v[:inputs["n_atoms"][i]] + single_results[k] = v[: inputs["n_atoms"][i]] unpacked_results.append(single_results) return unpacked_results @@ -234,7 +233,9 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): def batch_eval(self, data, batch_size=64, silent=False): if self.model is None: self.initialize(data[0]) - dataset = initialize_dataset(self.model_config, RawDataset(atoms_list=data), calc_stats=False) + dataset = initialize_dataset( + self.model_config, RawDataset(atoms_list=data), calc_stats=False + ) dataset.set_batch_size(batch_size) evaluated_data = [] @@ -242,7 +243,9 @@ def batch_eval(self, data, batch_size=64, silent=False): ds = dataset.batch() batched_model = jax.jit(jax.vmap(self.model, in_axes=(0, 0, 0, 0, 0))) - pbar = trange(n_data, desc="Computing features", ncols=100, leave=True, disable=silent) + pbar = trange( + n_data, desc="Computing features", ncols=100, leave=True, disable=silent + ) for i, (inputs, _) in enumerate(ds): positions_b, Z_b, neighbor_b, box_b, offsets_b = ( inputs["positions"], diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..684203eb 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,10 +109,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From d1c86e641306de3fecb8170abe8b77ab8f1ce90a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:15:41 +0000 Subject: [PATCH 017/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/data/input_pipeline.py | 14 ++++++-------- apax/train/trainer.py | 10 ++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 3e53fa33..6832c587 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -134,14 +134,12 @@ def dataset_from_dicts( for key, val in labels["fixed"].items(): labels["fixed"][key] = tf.constant(val) - ds = tf.data.Dataset.from_tensor_slices( - ( - inputs["ragged"], - inputs["fixed"], - labels["ragged"], - labels["fixed"], - ) - ) + ds = tf.data.Dataset.from_tensor_slices(( + inputs["ragged"], + inputs["fixed"], + labels["ragged"], + labels["fixed"], + )) return ds diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 684203eb..0c96277b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,12 +109,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 6bc206b76a9aab31485a929955dcf2455181f948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 17:00:35 +0100 Subject: [PATCH 018/192] adde docstrings, type hints. Always check for num strucutres in batch. --- apax/md/ase_calc.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 43e1342b..cc485819 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -5,6 +5,7 @@ import jax import jax.numpy as jnp import numpy as np +import ase from ase.calculators.calculator import Calculator, all_changes from ase.calculators.singlepoint import SinglePointCalculator from jax_md import partition, quantity, space @@ -230,15 +231,36 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): self.results = {k: np.array(v, dtype=np.float64) for k, v in results.items()} self.results["energy"] = self.results["energy"].item() - def batch_eval(self, data, batch_size=64, silent=False): + def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bool=False) -> list[ase.Atoms]: + """Evaluate the model on a list of Atoms. This is preferable to assigning + the calculator to each Atoms instance for 2 reasons: + 1. Processing can be abtched, which is advantageous for larger datasets. + 2. Inputs are padded so no recompilation is triggered when evaluating + differently sized systems. + + Arguments + --------- + atoms_list : + List of Atoms to be evaluated. + batch_size: + Processing batch size. Does not affect results, + only speed and memory requirements. + silent: + Whether or not to suppress progress bars. + + Returns + ------- + evaluated_atoms_list: + List of Atoms with labels predicted by the model. + """ if self.model is None: - self.initialize(data[0]) + self.initialize(atoms_list[0]) dataset = initialize_dataset( - self.model_config, RawDataset(atoms_list=data), calc_stats=False + self.model_config, RawDataset(atoms_list=atoms_list), calc_stats=False ) dataset.set_batch_size(batch_size) - evaluated_data = [] + evaluated_atoms_list = [] n_data = dataset.n_data ds = dataset.batch() batched_model = jax.jit(jax.vmap(self.model, in_axes=(0, 0, 0, 0, 0))) @@ -256,13 +278,17 @@ def batch_eval(self, data, batch_size=64, silent=False): ) results = batched_model(positions_b, Z_b, neighbor_b, box_b, offsets_b) unpadded_results = unpack_results(results, inputs) - for j in range(batch_size): - atoms = data[i].copy() + + # for the last batch, the number of structures may be less than the batch_size, + # which is why we check this explicitely + num_strucutres_in_batch = results["energy"].shape[0] + for j in range(num_strucutres_in_batch): + atoms = atoms_list[i].copy() atoms.calc = SinglePointCalculator(atoms=atoms, **unpadded_results[j]) - evaluated_data.append(atoms) + evaluated_atoms_list.append(atoms) pbar.update(batch_size) pbar.close() - return evaluated_data + return evaluated_atoms_list def neighbor_calculable_with_jax(box, r_max): From 3b9fe79cd059708ddf7fd60b829777ed469c1c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 17:37:21 +0100 Subject: [PATCH 019/192] split atoms to arrays into functions for inputs and labels respectively --- apax/utils/convert.py | 85 +++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 3c3bd6a3..c7f24385 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -4,6 +4,16 @@ from ase.units import Ang, Bohr, Hartree, eV, kcal, kJ, mol from jax_md import space +DTYPE = np.float64 +unit_dict = { + "Ang": Ang, + "Bohr": Bohr, + "eV": eV, + "kcal/mol": kcal / mol, + "Hartree": Hartree, + "kJ/mol": kJ / mol, +} + def tf_to_jax_dict(data_dict: dict[str, list]) -> dict: """Converts a dict of tf.Tensors to a dict of jax.numpy.arrays. @@ -28,16 +38,14 @@ def prune_dict(data_dict): return pruned -def atoms_to_arrays( +def atoms_to_inputs( atoms_list: list[Atoms], pos_unit: str = "Ang", - energy_unit: str = "eV", -) -> tuple[dict[str, dict[str, list]], dict[str, dict[str, list]]]: - """Converts an list of ASE atoms to two dicts where all inputs and labels - are sorted by there shape (ragged/fixed), and property. Units are +) -> dict[str, dict[str, list]]: + """Converts an list of ASE atoms to a dict where all inputs + are sorted by their shape (ragged/fixed). Units are adjusted if ASE compatible and provided in the inputpipeline. - Parameters ---------- atoms_list : @@ -60,26 +68,7 @@ def atoms_to_arrays( "box": [], }, } - - labels = { - "ragged": { - "forces": [], - }, - "fixed": { - "energy": [], - "stress": [], - }, - } - DTYPE = np.float64 - - unit_dict = { - "Ang": Ang, - "Bohr": Bohr, - "eV": eV, - "kcal/mol": kcal / mol, - "Hartree": Hartree, - "kJ/mol": kJ / mol, - } + box = atoms_list[0].cell.array pbc = np.all(box > 1e-6) @@ -109,6 +98,42 @@ def atoms_to_arrays( inputs["ragged"]["numbers"].append(atoms.numbers) inputs["fixed"]["n_atoms"].append(len(atoms)) + + inputs["fixed"] = prune_dict(inputs["fixed"]) + inputs["ragged"] = prune_dict(inputs["ragged"]) + return inputs + + +def atoms_to_labels( + atoms_list: list[Atoms], + pos_unit: str = "Ang", + energy_unit: str = "eV", +) -> dict[str, dict[str, list]]: + """Converts an list of ASE atoms to a dict of labels + Units are adjusted if ASE compatible and provided in the inputpipeline. + + Parameters + ---------- + atoms_list : + List of all structures. Enties are ASE atoms objects. + + Returns + ------- + labels : + Labels are trainable system properties. + """ + + labels = { + "ragged": { + "forces": [], + }, + "fixed": { + "energy": [], + "stress": [], + }, + } + + for atoms in atoms_list: for key, val in atoms.calc.results.items(): if key == "forces": labels["ragged"][key].append( @@ -117,16 +142,14 @@ def atoms_to_arrays( elif key == "energy": labels["fixed"][key].append(val * unit_dict[energy_unit]) elif key == "stress": - stress = ( # TODO check whether we should transpose - atoms.get_stress(voigt=False) # .T + stress = ( + atoms.get_stress(voigt=False) * unit_dict[energy_unit] / (unit_dict[pos_unit] ** 3) * atoms.cell.volume ) labels["fixed"][key].append(stress) - inputs["fixed"] = prune_dict(inputs["fixed"]) labels["fixed"] = prune_dict(labels["fixed"]) - inputs["ragged"] = prune_dict(inputs["ragged"]) labels["ragged"] = prune_dict(labels["ragged"]) - return inputs, labels + return labels \ No newline at end of file From 282443258c7efa1af5a47a3f715fe0d0885832e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 17:40:25 +0100 Subject: [PATCH 020/192] made dataset from dicts independent of the number of spllied dicts --- apax/data/input_pipeline.py | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 3e53fa33..dd5178ab 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -7,7 +7,7 @@ import tensorflow as tf from apax.data.preprocessing import dataset_neighborlist, prefetch_to_single_device -from apax.utils.convert import atoms_to_arrays +from apax.utils.convert import atoms_to_inputs, atoms_to_labels log = logging.getLogger(__name__) @@ -99,7 +99,8 @@ def create_dict_dataset( pos_unit: str = "Ang", energy_unit: str = "eV", ) -> tuple[dict]: - inputs, labels = atoms_to_arrays(atoms_list, pos_unit, energy_unit) + inputs = atoms_to_inputs(atoms_list, pos_unit) + labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) if external_labels: for shape, label in external_labels.items(): @@ -119,29 +120,18 @@ def create_dict_dataset( def dataset_from_dicts( - inputs: Dict[str, np.ndarray], labels: Dict[str, np.ndarray] -) -> tf.data.Dataset: + *dicts_of_arrays: Dict[str, np.ndarray]) -> tf.data.Dataset: # tf.RaggedTensors should be created from `tf.ragged.stack` # instead of `tf.ragged.constant` for performance reasons. # See https://github.com/tensorflow/tensorflow/issues/47853 - for key, val in inputs["ragged"].items(): - inputs["ragged"][key] = tf.ragged.stack(val) - for key, val in inputs["fixed"].items(): - inputs["fixed"][key] = tf.constant(val) - - for key, val in labels["ragged"].items(): - labels["ragged"][key] = tf.ragged.stack(val) - for key, val in labels["fixed"].items(): - labels["fixed"][key] = tf.constant(val) - - ds = tf.data.Dataset.from_tensor_slices( - ( - inputs["ragged"], - inputs["fixed"], - labels["ragged"], - labels["fixed"], - ) - ) + for doa in dicts_of_arrays: + for key, val in doa["ragged"].items(): + doa["ragged"][key] = tf.ragged.stack(val) + for key, val in doa["fixed"].items(): + doa["fixed"][key] = tf.constant(val) + + tensors = (doa["ragged"], doa["fixed"] for doa in dicts_of_arrays) + ds = tf.data.Dataset.from_tensor_slices(tensors) return ds @@ -151,8 +141,8 @@ class AtomisticDataset: def __init__( self, inputs, - labels, n_epoch: int, + labels=None, buffer_size: int = 1000, ) -> None: """Processes inputs/labels and makes them accessible for training. From ffae6a4a1c8484ee14a11624151428b7f6f4f7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 26 Feb 2024 18:21:05 +0100 Subject: [PATCH 021/192] allow for datasets without labels --- apax/data/initialization.py | 13 ++-- apax/data/input_pipeline.py | 125 ++++++++++++++++++++++++++---------- apax/md/ase_calc.py | 5 +- apax/utils/convert.py | 5 +- 4 files changed, 106 insertions(+), 42 deletions(-) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 2f7ad964..4d1b540d 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -5,7 +5,7 @@ import numpy as np from ase import Atoms -from apax.data.input_pipeline import AtomisticDataset, create_dict_dataset +from apax.data.input_pipeline import AtomisticDataset, process_inputs, process_labels from apax.data.statistics import compute_scale_shift_parameters from apax.utils.data import load_data, split_atoms, split_idxs, split_label @@ -53,15 +53,20 @@ def load_data_files(data_config): def initialize_dataset(config, raw_ds, calc_stats: bool = True): - inputs, labels = create_dict_dataset( + inputs = process_inputs( raw_ds.atoms_list, r_max=config.model.r_max, - external_labels=raw_ds.additional_labels, disable_pbar=config.progress_bar.disable_nl_pbar, pos_unit=config.data.pos_unit, + ) + labels = process_labels( + raw_ds.atoms_list, + external_labels=raw_ds.additional_labels, + pos_unit=config.data.pos_unit, energy_unit=config.data.energy_unit, ) + if calc_stats: ds_stats = compute_scale_shift_parameters( inputs, @@ -74,8 +79,8 @@ def initialize_dataset(config, raw_ds, calc_stats: bool = True): dataset = AtomisticDataset( inputs, - labels, config.n_epochs, + labels=labels, buffer_size=config.data.shuffle_buffer_size, ) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index dd5178ab..7f52b23b 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -36,16 +36,16 @@ def __init__(self, max_atoms: int, max_nbrs: int) -> None: self.max_nbrs = max_nbrs def __call__( - self, r_inputs: dict, f_inputs: dict, r_labels: dict, f_labels: dict + self, inputs: dict, labels: dict = None ) -> tuple[dict, dict]: """ Arguments --------- r_inputs : - Inputs of ragged shape. Untrainable system-determining properties. + Inputs of ragged shape. f_inputs : - Inputs of fixed shape. Untrainable system-determining properties. + Inputs of fixed shape. r_labels : Labels of ragged shape. Trainable system properties. f_labels : @@ -58,6 +58,8 @@ def __call__( labels: Contains all labels and all entries are uniformly shaped. """ + r_inputs = inputs["ragged"] + f_inputs = inputs["fixed"] for key, val in r_inputs.items(): if self.max_atoms is None: r_inputs[key] = val.to_tensor() @@ -75,37 +77,71 @@ def __call__( padded_shape = [shape[0], self.max_atoms, shape[2]] # batch, atoms, 3 r_inputs[key] = val.to_tensor(shape=padded_shape) - for key, val in r_labels.items(): - if self.max_atoms is None: - r_labels[key] = val.to_tensor() - else: - padded_shape = [shape[0], self.max_atoms, shape[2]] - r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) - - inputs = r_inputs.copy() - inputs.update(f_inputs) - - labels = r_labels.copy() - labels.update(f_labels) - - return inputs, labels - - -def create_dict_dataset( + new_inputs = r_inputs.copy() + new_inputs.update(f_inputs) + + + if labels: + r_labels = labels["ragged"] + f_labels = labels["fixed"] + for key, val in r_labels.items(): + if self.max_atoms is None: + r_labels[key] = val.to_tensor() + else: + padded_shape = [shape[0], self.max_atoms, shape[2]] + r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) + + new_labels = r_labels.copy() + new_labels.update(f_labels) + + return new_inputs, new_labels + else: + return new_inputs + # for key, val in r_inputs.items(): + # if self.max_atoms is None: + # r_inputs[key] = val.to_tensor() + # elif key == "idx": + # shape = r_inputs[key].shape + # padded_shape = [shape[0], shape[1], self.max_nbrs] # batch, ij, nbrs + # elif key == "offsets": + # shape = r_inputs[key].shape + # padded_shape = [shape[0], self.max_nbrs, 3] # batch, ij, nbrs + # elif key == "numbers": + # shape = r_inputs[key].shape + # padded_shape = [shape[0], self.max_atoms] # batch, atoms + # else: + # shape = r_inputs[key].shape + # padded_shape = [shape[0], self.max_atoms, shape[2]] # batch, atoms, 3 + # r_inputs[key] = val.to_tensor(shape=padded_shape) + + # inputs = r_inputs.copy() + # inputs.update(f_inputs) + + + # if r_labels and f_labels: + # for key, val in r_labels.items(): + # if self.max_atoms is None: + # r_labels[key] = val.to_tensor() + # else: + # padded_shape = [shape[0], self.max_atoms, shape[2]] + # r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) + + # labels = r_labels.copy() + # labels.update(f_labels) + + + # return inputs, labels + # else: + # return inputs + + +def process_inputs( atoms_list: list, r_max: float, - external_labels: dict = {}, disable_pbar=False, pos_unit: str = "Ang", - energy_unit: str = "eV", -) -> tuple[dict]: +) -> dict: inputs = atoms_to_inputs(atoms_list, pos_unit) - labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) - - if external_labels: - for shape, label in external_labels.items(): - labels[shape].update(label) - idx, offsets = dataset_neighborlist( inputs["ragged"]["positions"], box=inputs["fixed"]["box"], @@ -116,7 +152,21 @@ def create_dict_dataset( inputs["ragged"]["idx"] = idx inputs["ragged"]["offsets"] = offsets - return inputs, labels + return inputs + + +def process_labels( + atoms_list: list, + external_labels: dict = {}, + pos_unit: str = "Ang", + energy_unit: str = "eV", +) -> tuple[dict]: + labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) + + if external_labels: + for shape, label in external_labels.items(): + labels[shape].update(label) + return labels def dataset_from_dicts( @@ -130,8 +180,13 @@ def dataset_from_dicts( for key, val in doa["fixed"].items(): doa["fixed"][key] = tf.constant(val) - tensors = (doa["ragged"], doa["fixed"] for doa in dicts_of_arrays) - ds = tf.data.Dataset.from_tensor_slices(tensors) + # tensors = [] + # for doa in dicts_of_arrays: + # tensors.append(doa["ragged"]) + # tensors.append(doa["fixed"]) + # print(*tensors) + # quit() + ds = tf.data.Dataset.from_tensor_slices(*dicts_of_arrays) return ds @@ -173,7 +228,11 @@ def __init__( self.n_data = len(inputs["fixed"]["n_atoms"]) - self.ds = dataset_from_dicts(inputs, labels) + + if labels: + self.ds = dataset_from_dicts(inputs, labels) + else: + self.ds = dataset_from_dicts(inputs) def set_batch_size(self, batch_size: int): self.batch_size = self.validate_batch_size(batch_size) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index cc485819..3ea005b3 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -268,15 +268,14 @@ def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bo pbar = trange( n_data, desc="Computing features", ncols=100, leave=True, disable=silent ) - for i, (inputs, _) in enumerate(ds): - positions_b, Z_b, neighbor_b, box_b, offsets_b = ( + for i, inputs in enumerate(ds): + results = batched_model( inputs["positions"], inputs["numbers"], inputs["idx"], inputs["box"], inputs["offsets"], ) - results = batched_model(positions_b, Z_b, neighbor_b, box_b, offsets_b) unpadded_results = unpack_results(results, inputs) # for the last batch, the number of structures may be less than the batch_size, diff --git a/apax/utils/convert.py b/apax/utils/convert.py index c7f24385..6c333223 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -132,6 +132,8 @@ def atoms_to_labels( "stress": [], }, } + if not atoms_list[0].calc: + return None for atoms in atoms_list: for key, val in atoms.calc.results.items(): @@ -146,9 +148,8 @@ def atoms_to_labels( atoms.get_stress(voigt=False) * unit_dict[energy_unit] / (unit_dict[pos_unit] ** 3) - * atoms.cell.volume ) - labels["fixed"][key].append(stress) + labels["fixed"][key].append(stress * atoms.cell.volume) labels["fixed"] = prune_dict(labels["fixed"]) labels["ragged"] = prune_dict(labels["ragged"]) From 07b59ccdfacb6aa695101539c6736d0389119c6c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:22:11 +0000 Subject: [PATCH 022/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 6c333223..fcbf3907 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -153,4 +153,4 @@ def atoms_to_labels( labels["fixed"] = prune_dict(labels["fixed"]) labels["ragged"] = prune_dict(labels["ragged"]) - return labels \ No newline at end of file + return labels From 8983ad88d9d22399c532960e0b21ba1fe04602f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 10:15:10 +0100 Subject: [PATCH 023/192] started removing jaxmd --- apax/data/preprocessing.py | 5 +- .../descriptor/gaussian_moment_descriptor.py | 4 +- apax/layers/empirical.py | 4 +- apax/md/ase_calc.py | 14 +- apax/md/nvt.py | 8 +- apax/model/gmnn.py | 20 +- apax/utils/convert.py | 4 +- apax/utils/jax_md_reduced/__init__.py | 4 +- apax/utils/jax_md_reduced/partition.py | 4 + apax/utils/jax_md_reduced/quantity.py | 0 apax/utils/jax_md_reduced/simulate.py | 0 apax/utils/jax_md_reduced/space.py | 235 ++++++++++++++++++ apax/utils/jax_md_reduced/util.py | 0 13 files changed, 270 insertions(+), 32 deletions(-) create mode 100644 apax/utils/jax_md_reduced/quantity.py create mode 100644 apax/utils/jax_md_reduced/simulate.py create mode 100644 apax/utils/jax_md_reduced/space.py create mode 100644 apax/utils/jax_md_reduced/util.py diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index b15a1b2a..fd1309a4 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -7,7 +7,6 @@ import jax.numpy as jnp import numpy as np from ase import Atoms -from jax_md import partition, space from matscipy.neighbours import neighbour_list from tqdm import trange @@ -22,14 +21,14 @@ def initialize_nbr_fn(atoms: Atoms, cutoff: float) -> Callable: box = jnp.asarray(atoms.cell.array) if np.all(box < 1e-6): - displacement_fn, _ = space.free() + displacement_fn, _ = jax_md_reduced.space.free() box = default_box neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_or_metric=displacement_fn, box=box, r_cutoff=cutoff, - format=partition.Sparse, + format=jax_md_reduced.partition.Sparse, fractional_coordinates=False, ) diff --git a/apax/layers/descriptor/gaussian_moment_descriptor.py b/apax/layers/descriptor/gaussian_moment_descriptor.py index 061f01ee..a176e367 100644 --- a/apax/layers/descriptor/gaussian_moment_descriptor.py +++ b/apax/layers/descriptor/gaussian_moment_descriptor.py @@ -4,8 +4,8 @@ import flax.linen as nn import jax.numpy as jnp from jax import vmap -from jax_md import space +from apax.utils import jax_md_reduced from apax.layers.descriptor.basis_functions import RadialFunction from apax.layers.descriptor.moments import geometric_moments from apax.layers.descriptor.triangular_indices import tril_2d_indices, tril_3d_indices @@ -22,7 +22,7 @@ def setup(self): self.r_max = self.radial_fn.r_max self.n_radial = self.radial_fn._n_radial - self.distance = vmap(space.distance, 0, 0) + self.distance = vmap(jax_md_reduced.space.distance, 0, 0) self.triang_idxs_2d = tril_2d_indices(self.n_radial) self.triang_idxs_3d = tril_3d_indices(self.n_radial) diff --git a/apax/layers/empirical.py b/apax/layers/empirical.py index 1d8e2d27..e3c41669 100644 --- a/apax/layers/empirical.py +++ b/apax/layers/empirical.py @@ -5,8 +5,8 @@ import jax.numpy as jnp import numpy as np from jax import vmap -from jax_md import space +from apax.utils import jax_md_reduced from apax.layers.masking import mask_by_neighbor from apax.utils.math import fp64_sum @@ -24,7 +24,7 @@ class ZBLRepulsion(EmpiricalEnergyTerm): apply_mask: bool = True def setup(self): - self.distance = vmap(space.distance, 0, 0) + self.distance = vmap(jax_md_reduced.space.distance, 0, 0) self.ke = 14.3996 diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 3a69d2e6..87cf9bde 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -6,7 +6,7 @@ import jax.numpy as jnp import numpy as np from ase.calculators.calculator import Calculator, all_changes -from jax_md import partition, quantity, space +from jax_md import quantity from matscipy.neighbours import neighbour_list from apax.model import ModelBuilder @@ -37,9 +37,9 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ if neigbor_from_jax: if np.all(box < 1e-6): - displacement_fn, _ = space.free() + displacement_fn, _ = jax_md_reduced.space.free() else: - displacement_fn, _ = space.periodic_general(box, fractional_coordinates=True) + displacement_fn, _ = jax_md_reduced.space.periodic_general(box, fractional_coordinates=True) neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_fn, @@ -48,7 +48,7 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ dr_threshold, fractional_coordinates=True, disable_cell_list=True, - format=partition.Sparse, + format=jax_md_reduced.partition.Sparse, ) Z = jnp.asarray(atomic_numbers) @@ -154,7 +154,7 @@ def initialize(self, atoms): positions = jnp.asarray(atoms.positions, dtype=jnp.float64) box = atoms.cell.array.T inv_box = jnp.linalg.inv(box) - positions = space.transform(inv_box, positions) # frac coords + positions = jax_md_reduced.space.transform(inv_box, positions) # frac coords self.neighbors = self.neighbor_fn.allocate(positions, box=box) else: self.neighbors = self.neighbor_fn.allocate(positions) @@ -209,7 +209,7 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): else: self.set_neighbours_and_offsets(atoms, box) - positions = np.array(space.transform(np.linalg.inv(box), atoms.positions)) + positions = np.array(jax_md_reduced.space.transform(np.linalg.inv(box), atoms.positions)) results = self.step(positions, self.neighbors, box, self.offsets) @@ -250,7 +250,7 @@ def step_fn(positions, neighbor, box): if np.any(atoms.get_cell().lengths() > 1e-6): box = box.T inv_box = jnp.linalg.inv(box) - positions = space.transform(inv_box, positions) + positions = jax_md_reduced.space.transform(inv_box, positions) neighbor = neighbor.update(positions, box=box) else: neighbor = neighbor.update(positions) diff --git a/apax/md/nvt.py b/apax/md/nvt.py index 05c59070..8c132347 100644 --- a/apax/md/nvt.py +++ b/apax/md/nvt.py @@ -10,7 +10,7 @@ from ase.io import read from flax.training import checkpoints from jax.experimental.host_callback import barrier_wait, id_tap -from jax_md import partition, quantity, simulate, space +from jax_md import quantity, simulate from tqdm import trange from tqdm.contrib.logging import logging_redirect_tqdm @@ -340,7 +340,7 @@ def md_setup(model_config: Config, md_config: MDConfig): r_max = model_config.model.r_max log.info("initializing model") if np.all(system.box < 1e-6): - displacement_fn, shift_fn = space.free() + displacement_fn, shift_fn = jax_md_reduced.space.free() else: heights = heights_of_box_sides(system.box) @@ -356,7 +356,7 @@ def md_setup(model_config: Config, md_config: MDConfig): f"one cell vector direction {heights/2} < {r_max}", "can not calculate the correct neighbors", ) - displacement_fn, shift_fn = space.periodic_general( + displacement_fn, shift_fn = jax_md_reduced.space.periodic_general( system.box, fractional_coordinates=True ) @@ -370,7 +370,7 @@ def md_setup(model_config: Config, md_config: MDConfig): r_max, md_config.dr_threshold, fractional_coordinates=True, - format=partition.Sparse, + format=jax_md_reduced.partition.Sparse, disable_cell_list=True, ) diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index c846aeae..2e924409 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -7,7 +7,6 @@ import jax.numpy as jnp import numpy as np from jax import vmap -from jax_md import partition, space from jax_md.util import Array from apax.layers.descriptor.gaussian_moment_descriptor import GaussianMomentDescriptor @@ -17,23 +16,24 @@ from apax.layers.readout import AtomisticReadout from apax.layers.scaling import PerElementScaleShift from apax.utils.math import fp64_sum +from apax.utils import jax_md_reduced DisplacementFn = Callable[[Array, Array], Array] -MDModel = Tuple[partition.NeighborFn, Callable, Callable] +MDModel = Tuple[jax_md_reduced.partition.NeighborFn, Callable, Callable] log = logging.getLogger(__name__) def canonicalize_neighbors(neighbor): - return neighbor.idx if isinstance(neighbor, partition.NeighborList) else neighbor + return neighbor.idx if isinstance(neighbor, jax_md_reduced.NeighborList) else neighbor def disp_fn(ri, rj, perturbation, box): - dR = space.pairwise_displacement(ri, rj) - dR = space.transform(box, dR) + dR = jax_md_reduced.space.pairwise_displacement(ri, rj) + dR = jax_md_reduced.space.transform(box, dR) if perturbation is not None: - dR = dR + space.raw_transform(perturbation, dR) + dR = dR + jax_md_reduced.space.raw_transform(perturbation, dR) # https://github.com/mir-group/nequip/blob/c56f48fcc9b4018a84e1ed28f762fadd5bc763f1/nequip/nn/_grad_output.py#L267 # https://github.com/sirmarcel/glp/blob/main/glp/calculators/utils.py # other codes do R = R + strain, not dR @@ -78,8 +78,8 @@ class EnergyModel(nn.Module): def setup(self): if np.all(self.init_box < 1e-6): # gas phase training and predicting - displacement_fn = space.free()[0] - self.displacement = space.map_bond(displacement_fn) + displacement_fn = jax_md_reduced.space.free()[0] + self.displacement = jax_md_reduced.space.map_bond(displacement_fn) elif self.inference_disp_fn is None: # for training on periodic systems self.displacement = vmap(disp_fn, (0, 0, None, None), 0) @@ -91,7 +91,7 @@ def __call__( self, R: Array, Z: Array, - neighbor: Union[partition.NeighborList, Array], + neighbor: Union[jax_md_reduced.partition.NeighborList, Array], box, offsets, perturbation=None, @@ -138,7 +138,7 @@ def __call__( self, R: Array, Z: Array, - neighbor: Union[partition.NeighborList, Array], + neighbor: Union[jax_md_reduced.partition.NeighborList, Array], box, offsets, ): diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 3c3bd6a3..983b7e4d 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -2,7 +2,7 @@ import numpy as np from ase import Atoms from ase.units import Ang, Bohr, Hartree, eV, kcal, kJ, mol -from jax_md import space +from apax.utils import jax_md_reduced def tf_to_jax_dict(data_dict: dict[str, list]) -> dict: @@ -101,7 +101,7 @@ def atoms_to_arrays( inv_box = np.linalg.inv(box) inputs["ragged"]["positions"].append( np.array( - space.transform( + jax_md_reduced.space.transform( inv_box, (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) ) ) diff --git a/apax/utils/jax_md_reduced/__init__.py b/apax/utils/jax_md_reduced/__init__.py index 4304d0d5..8a63f8bf 100644 --- a/apax/utils/jax_md_reduced/__init__.py +++ b/apax/utils/jax_md_reduced/__init__.py @@ -1,3 +1,3 @@ -from apax.utils.jax_md_reduced import partition +from apax.utils.jax_md_reduced import partition, space, quantity -__all__ = ["partition"] +__all__ = ["partition", "space", "quantity"] diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 0f799160..870dd7f5 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -37,6 +37,10 @@ MetricFn = space.MetricFn MaskFn = Callable[[Array], Array] +NeighborFn = Callable[[Array, Optional[NeighborList], Optional[int]], + NeighborList] + +Sparse = NeighborListFormat.Sparse def neighbor_list( displacement_or_metric: DisplacementOrMetricFn, diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py new file mode 100644 index 00000000..e69de29b diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py new file mode 100644 index 00000000..e69de29b diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py new file mode 100644 index 00000000..040ec155 --- /dev/null +++ b/apax/utils/jax_md_reduced/space.py @@ -0,0 +1,235 @@ +def raw_transform(box: Box, R: Array) -> Array: + """Apply an affine transformation to positions. + + See `periodic_general` for a description of the semantics of `box`. + + Args: + box: An affine transformation described in `periodic_general`. + R: Array of positions. Should have shape `(..., spatial_dimension)`. + + Returns: + A transformed array positions of shape `(..., spatial_dimension)`. + """ + if jnp.isscalar(box) or box.size == 1: + return R * box + elif box.ndim == 1: + indices = _get_free_indices(R.ndim - 1) + 'i' + return jnp.einsum(f'i,{indices}->{indices}', box, R) + elif box.ndim == 2: + free_indices = _get_free_indices(R.ndim - 1) + left_indices = free_indices + 'j' + right_indices = free_indices + 'i' + return jnp.einsum(f'ij,{left_indices}->{right_indices}', box, R) + raise ValueError(('Box must be either: a scalar, a vector, or a matrix. ' + f'Found {box}.')) + +@custom_jvp +def transform(box: Box, R: Array) -> Array: + """Apply an affine transformation to positions. + + See `periodic_general` for a description of the semantics of `box`. + + Args: + box: An affine transformation described in `periodic_general`. + R: Array of positions. Should have shape `(..., spatial_dimension)`. + + Returns: + A transformed array positions of shape `(..., spatial_dimension)`. + """ + return raw_transform(box, R) + + +@transform.defjvp +def transform_jvp(primals, tangents): + box, R = primals + dbox, dR = tangents + return (transform(box, R), dR + transform(dbox, R)) + +def pairwise_displacement(Ra: Array, Rb: Array) -> Array: + """Compute a matrix of pairwise displacements given two sets of positions. + + Args: + Ra: Vector of positions; `ndarray(shape=[spatial_dim])`. + Rb: Vector of positions; `ndarray(shape=[spatial_dim])`. + + Returns: + Matrix of displacements; `ndarray(shape=[spatial_dim])`. + """ + if len(Ra.shape) != 1: + msg = ( + 'Can only compute displacements between vectors. To compute ' + 'displacements between sets of vectors use vmap or TODO.' + ) + raise ValueError(msg) + + if Ra.shape != Rb.shape: + msg = 'Can only compute displacement between vectors of equal dimension.' + raise ValueError(msg) + + return Ra - Rb + +def free() -> Space: + """Free boundary conditions.""" + def displacement_fn(Ra: Array, Rb: Array, perturbation: Optional[Array]=None, + **unused_kwargs) -> Array: + dR = pairwise_displacement(Ra, Rb) + if perturbation is not None: + dR = raw_transform(perturbation, dR) + return dR + def shift_fn(R: Array, dR: Array, **unused_kwargs) -> Array: + return R + dR + return displacement_fn, shift_fn + + +def periodic_general(box: Box, + fractional_coordinates: bool=True, + wrapped: bool=True) -> Space: + """Periodic boundary conditions on a parallelepiped. + + This function defines a simulation on a parallelepiped, :math:`X`, formed by + applying an affine transformation, :math:`T`, to the unit hypercube + :math:`U = [0, 1]^d` along with periodic boundary conditions across all + of the faces. + + Formally, the space is defined such that :math:`X = {Tu : u \in [0, 1]^d}`. + + The affine transformation, :math:`T`, can be specified in a number of different + ways. For a parallelepiped that is: 1) a cube of side length :math:`L`, the affine + transformation can simply be a scalar; 2) an orthorhombic unit cell can be + specified by a vector `[Lx, Ly, Lz]` of lengths for each axis; 3) a general + triclinic cell can be specified by an upper triangular matrix. + + There are a number of ways to parameterize a simulation on :math:`X`. + `periodic_general` supports two parametrizations of :math:`X` that can be selected + using the `fractional_coordinates` keyword argument. + + 1) When `fractional_coordinates=True`, particle positions are stored in the + unit cube, :math:`u\in U`. Here, the displacement function computes the + displacement between :math:`x, y \in X` as :math:`d_X(x, y) = Td_U(u, v)` where + :math:`d_U` is the displacement function on the unit cube, :math:`U`, :math:`x = Tu`, and + :math:`v = Tv` with :math:`u, v \in U`. The derivative of the displacement function + is defined so that derivatives live in :math:`X` (as opposed to being + backpropagated to :math:`U`). The shift function, `shift_fn(R, dR)` is defined + so that :math:`R` is expected to lie in :math:`U` while :math:`dR` should lie in :math:`X`. This + combination enables code such as `shift_fn(R, force_fn(R))` to work as + intended. + + 2) When `fractional_coordinates=False`, particle positions are stored in + the parallelepiped :math:`X`. Here, for :math:`x, y \in X`, the displacement function + is defined as :math:`d_X(x, y) = Td_U(T^{-1}x, T^{-1}y)`. Since there is an + extra multiplication by :math:`T^{-1}`, this parameterization is typically + slower than `fractional_coordinates=False`. As in 1), the displacement + function is defined to compute derivatives in :math:`X`. The shift function + is defined so that :math:`R` and :math:`dR` should both lie in :math:`X`. + + Example: + + .. code-block:: python + + from jax import random + side_length = 10.0 + disp_frac, shift_frac = periodic_general(side_length, + fractional_coordinates=True) + disp_real, shift_real = periodic_general(side_length, + fractional_coordinates=False) + + # Instantiate random positions in both parameterizations. + R_frac = random.uniform(random.PRNGKey(0), (4, 3)) + R_real = side_length * R_frac + + # Make some shift vectors. + dR = random.normal(random.PRNGKey(0), (4, 3)) + + disp_real(R_real[0], R_real[1]) == disp_frac(R_frac[0], R_frac[1]) + transform(side_length, shift_frac(R_frac, 1.0)) == shift_real(R_real, 1.0) + + It is often desirable to deform a simulation cell either: using a finite + deformation during a simulation, or using an infinitesimal deformation while + computing elastic constants. To do this using fractional coordinates, we can + supply a new affine transformation as `displacement_fn(Ra, Rb, box=new_box)`. + When using real coordinates, we can specify positions in a space :math:`X` defined + by an affine transformation :math:`T` and compute displacements in a deformed space + :math:`X'` defined by an affine transformation :math:`T'`. This is done by writing + `displacement_fn(Ra, Rb, new_box=new_box)`. + + There are a few caveats when using `periodic_general`. `periodic_general` + uses the minimum image convention, and so it will fail for potentials whose + cutoff is longer than the half of the side-length of the box. It will also + fail to find the correct image when the box is too deformed. We hope to add a + more robust box for small simulations soon (TODO) along with better error + checking. In the meantime caution is recommended. + + Args: + box: A `(spatial_dim, spatial_dim)` affine transformation. + fractional_coordinates: A boolean specifying whether positions are stored + in the parallelepiped or the unit cube. + wrapped: A boolean specifying whether or not particle positions are + remapped back into the box after each step + Returns: + `(displacement_fn, shift_fn)` tuple. + """ + inv_box = inverse(box) + + def displacement_fn(Ra, Rb, perturbation=None, **kwargs): + _box, _inv_box = box, inv_box + + if 'box' in kwargs: + _box = kwargs['box'] + + if not fractional_coordinates: + _inv_box = inverse(_box) + + if 'new_box' in kwargs: + _box = kwargs['new_box'] + + if not fractional_coordinates: + Ra = transform(_inv_box, Ra) + Rb = transform(_inv_box, Rb) + + dR = periodic_displacement(f32(1.0), pairwise_displacement(Ra, Rb)) + dR = transform(_box, dR) + + if perturbation is not None: + dR = raw_transform(perturbation, dR) + + return dR + + def u(R, dR): + if wrapped: + return periodic_shift(f32(1.0), R, dR) + return R + dR + + def shift_fn(R, dR, **kwargs): + if not fractional_coordinates and not wrapped: + return R + dR + + _box, _inv_box = box, inv_box + if 'box' in kwargs: + _box = kwargs['box'] + _inv_box = inverse(_box) + + if 'new_box' in kwargs: + _box = kwargs['new_box'] + + dR = transform(_inv_box, dR) + if not fractional_coordinates: + R = transform(_inv_box, R) + + R = u(R, dR) + + if not fractional_coordinates: + R = transform(_box, R) + return R + + return displacement_fn, shift_fn + +def distance(dR: Array) -> Array: + """Computes distances. + + Args: + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of distances; `ndarray(shape=[...])`. + """ + dr = square_distance(dR) + return safe_mask(dr > 0, jnp.sqrt, dr) \ No newline at end of file diff --git a/apax/utils/jax_md_reduced/util.py b/apax/utils/jax_md_reduced/util.py new file mode 100644 index 00000000..e69de29b From 9e3de2706172cf05824fefe4269c40c75eac327f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 11:16:56 +0100 Subject: [PATCH 024/192] made option to read labels explicit --- apax/data/initialization.py | 17 ++++++++++------- apax/data/input_pipeline.py | 10 +++------- apax/utils/convert.py | 2 -- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 4d1b540d..9fc37204 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -52,19 +52,22 @@ def load_data_files(data_config): return train_raw_ds, val_raw_ds -def initialize_dataset(config, raw_ds, calc_stats: bool = True): +def initialize_dataset(config, raw_ds, calc_stats: bool = True, read_labels: bool =True): inputs = process_inputs( raw_ds.atoms_list, r_max=config.model.r_max, disable_pbar=config.progress_bar.disable_nl_pbar, pos_unit=config.data.pos_unit, ) - labels = process_labels( - raw_ds.atoms_list, - external_labels=raw_ds.additional_labels, - pos_unit=config.data.pos_unit, - energy_unit=config.data.energy_unit, - ) + if read_labels: + labels = process_labels( + raw_ds.atoms_list, + external_labels=raw_ds.additional_labels, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, + ) + else: + labels = None if calc_stats: diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 7f52b23b..a1e9d486 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -180,12 +180,7 @@ def dataset_from_dicts( for key, val in doa["fixed"].items(): doa["fixed"][key] = tf.constant(val) - # tensors = [] - # for doa in dicts_of_arrays: - # tensors.append(doa["ragged"]) - # tensors.append(doa["fixed"]) - # print(*tensors) - # quit() + # add check for more than 2 datasets ds = tf.data.Dataset.from_tensor_slices(*dicts_of_arrays) return ds @@ -227,9 +222,10 @@ def __init__( self.max_nbrs = max_nbrs self.n_data = len(inputs["fixed"]["n_atoms"]) - + inputs = process_inputs(inputs) if labels: + labels = process_labels(labels) self.ds = dataset_from_dicts(inputs, labels) else: self.ds = dataset_from_dicts(inputs) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 6c333223..f296cd1b 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -132,8 +132,6 @@ def atoms_to_labels( "stress": [], }, } - if not atoms_list[0].calc: - return None for atoms in atoms_list: for key, val in atoms.calc.results.items(): From 7fdc3316f092d9aaa63e6de6f59521423d000393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 12:18:42 +0100 Subject: [PATCH 025/192] attach external labels directly to atoms, removed RawDataset --- apax/bal/api.py | 5 ++--- apax/data/initialization.py | 41 ++++++++++++------------------------- apax/data/input_pipeline.py | 5 +++-- apax/md/ase_calc.py | 4 ++-- apax/train/eval.py | 9 +++----- apax/utils/data.py | 34 ++++-------------------------- 6 files changed, 27 insertions(+), 71 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index b4eecae1..b905c4d9 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -8,7 +8,6 @@ from tqdm import trange from apax.bal import feature_maps, kernel, selection, transforms -from apax.data.initialization import RawDataset from apax.data.input_pipeline import AtomisticDataset from apax.model.builder import ModelBuilder from apax.model.gmnn import EnergyModel @@ -55,7 +54,7 @@ def compute_features(feature_fn, dataset: AtomisticDataset): ds = dataset.batch() pbar = trange(n_data, desc="Computing features", ncols=100, leave=True) - for i, (inputs, _) in enumerate(ds): + for inputs in ds: g = feature_fn(inputs) features.append(np.asarray(g)) pbar.update(g.shape[0]) @@ -88,7 +87,7 @@ def kernel_selection( n_train = len(train_atoms) dataset = initialize_dataset( - config, RawDataset(atoms_list=train_atoms + pool_atoms), calc_stats=False + config, train_atoms + pool_atoms, calc_stats=False ) dataset.set_batch_size(processing_batch_size) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 9fc37204..4615abde 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -7,28 +7,21 @@ from apax.data.input_pipeline import AtomisticDataset, process_inputs, process_labels from apax.data.statistics import compute_scale_shift_parameters -from apax.utils.data import load_data, split_atoms, split_idxs, split_label +from apax.utils.data import load_data, split_atoms, split_idxs log = logging.getLogger(__name__) -@dataclasses.dataclass -class RawDataset: - atoms_list: list[Atoms] - additional_labels: Optional[dict] = None - - def load_data_files(data_config): log.info("Running Input Pipeline") if data_config.data_path is not None: log.info(f"Read data file {data_config.data_path}") - atoms_list, label_dict = load_data(data_config.data_path) + atoms_list = load_data(data_config.data_path) train_idxs, val_idxs = split_idxs( atoms_list, data_config.n_train, data_config.n_valid ) train_atoms_list, val_atoms_list = split_atoms(atoms_list, train_idxs, val_idxs) - train_label_dict, val_label_dict = split_label(label_dict, train_idxs, val_idxs) np.savez( data_config.model_version_path / "train_val_idxs", @@ -39,36 +32,28 @@ def load_data_files(data_config): elif data_config.train_data_path and data_config.val_data_path is not None: log.info(f"Read training data file {data_config.train_data_path}") log.info(f"Read validation data file {data_config.val_data_path}") - train_atoms_list, train_label_dict = load_data(data_config.train_data_path) - val_atoms_list, val_label_dict = load_data(data_config.val_data_path) + train_atoms_list = load_data(data_config.train_data_path) + val_atoms_list = load_data(data_config.val_data_path) else: raise ValueError("input data path/paths not defined") - train_raw_ds = RawDataset( - atoms_list=train_atoms_list, additional_labels=train_label_dict - ) - val_raw_ds = RawDataset(atoms_list=val_atoms_list, additional_labels=val_label_dict) + return train_atoms_list, val_atoms_list - return train_raw_ds, val_raw_ds - -def initialize_dataset(config, raw_ds, calc_stats: bool = True, read_labels: bool =True): +def initialize_dataset(config, raw_ds, read_labels: list[str] = ["energy", "forces"], calc_stats: bool = True): inputs = process_inputs( raw_ds.atoms_list, r_max=config.model.r_max, disable_pbar=config.progress_bar.disable_nl_pbar, pos_unit=config.data.pos_unit, ) - if read_labels: - labels = process_labels( - raw_ds.atoms_list, - external_labels=raw_ds.additional_labels, - pos_unit=config.data.pos_unit, - energy_unit=config.data.energy_unit, - ) - else: - labels = None - + labels = process_labels( + raw_ds.atoms_list, + read_labels=read_labels, + external_labels=raw_ds.additional_labels, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, + ) if calc_stats: ds_stats = compute_scale_shift_parameters( diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index a1e9d486..1ad2e846 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -157,10 +157,13 @@ def process_inputs( def process_labels( atoms_list: list, + read_labels, external_labels: dict = {}, pos_unit: str = "Ang", energy_unit: str = "eV", ) -> tuple[dict]: + if len(read_labels) == 0: + return None labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) if external_labels: @@ -222,10 +225,8 @@ def __init__( self.max_nbrs = max_nbrs self.n_data = len(inputs["fixed"]["n_atoms"]) - inputs = process_inputs(inputs) if labels: - labels = process_labels(labels) self.ds = dataset_from_dicts(inputs, labels) else: self.ds = dataset_from_dicts(inputs) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 3ea005b3..ef13a998 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -12,7 +12,7 @@ from matscipy.neighbours import neighbour_list from tqdm import trange -from apax.data.initialization import RawDataset, initialize_dataset +from apax.data.initialization import initialize_dataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters from apax.utils import jax_md_reduced @@ -256,7 +256,7 @@ def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bo if self.model is None: self.initialize(atoms_list[0]) dataset = initialize_dataset( - self.model_config, RawDataset(atoms_list=atoms_list), calc_stats=False + self.model_config, atoms_list, calc_stats=False ) dataset.set_batch_size(batch_size) diff --git a/apax/train/eval.py b/apax/train/eval.py index eba47efe..01ee0681 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -8,7 +8,7 @@ from tqdm import trange from apax.config import parse_config -from apax.data.initialization import RawDataset, initialize_dataset +from apax.data.initialization import initialize_dataset from apax.model import ModelBuilder from apax.train.callbacks import initialize_callbacks from apax.train.checkpoints import restore_single_parameters @@ -38,7 +38,7 @@ def load_test_data( os.makedirs(eval_path, exist_ok=True) if config.data.data_path is not None: log.info(f"Read data file {config.data.data_path}") - atoms_list, label_dict = load_data(config.data.data_path) + atoms_list = load_data(config.data.data_path) idxs_dict = np.load(model_version_path / "train_val_idxs.npz") @@ -53,7 +53,6 @@ def load_test_data( ) atoms_list, _ = split_atoms(atoms_list, test_idxs) - label_dict, _ = split_label(label_dict, test_idxs) elif config.data.test_data_path is not None: log.info(f"Read test data file {config.data.test_data_path}") @@ -64,8 +63,7 @@ def load_test_data( else: raise ValueError("input data path/paths not defined") - test_raw_ds = RawDataset(atoms_list=atoms_list, additional_labels=label_dict) - return test_raw_ds + return atoms_list def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=False): @@ -138,7 +136,6 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): ) model = jax.vmap(model.apply, in_axes=(None, 0, 0, 0, 0, 0)) - config, params = restore_single_parameters(model_version_path) predict( diff --git a/apax/utils/data.py b/apax/utils/data.py index c7e78e88..559f0975 100644 --- a/apax/utils/data.py +++ b/apax/utils/data.py @@ -50,7 +50,6 @@ def load_data(data_path): List of all structures where entries are ASE atoms objects. """ - external_labels = {} # TODO external labels can be included via hdf5 files only? this would clean up a lot try: @@ -66,20 +65,14 @@ def load_data(data_path): if label_path.is_file(): log.info(f"Loading non ASE labels from {label_path.as_posix()}") - label_dict = np.load(label_path.as_posix(), allow_pickle=True) - unique_shape = np.unique(label_dict["shape"]) - for shape in unique_shape: - external_labels.update({shape: {}}) - - i = 0 + # check if len atoms == len labels for key, val in label_dict.items(): - if key != "shape": - external_labels[label_dict["shape"][i]].update({key: val}) - i += 1 + for a, v in zip(atoms_list, val): + a.calc.results[key] = v - return atoms_list, external_labels + return atoms_list def split_idxs(atoms_list, n_train, n_valid): @@ -119,22 +112,3 @@ def split_atoms(atoms_list, train_idxs, val_idxs=None): val_atoms_list = [] return train_atoms_list, val_atoms_list - - -def split_label(external_labels, train_idxs, val_idxs=None): - train_label_dict, val_label_dict = ({}, {}) - - if val_idxs is not None: - for shape, labels in external_labels.items(): - train_label_dict.update({shape: {}}) - val_label_dict.update({shape: {}}) - for label, vals in labels.items(): - train_label_dict[shape].update({label: vals[train_idxs]}) - val_label_dict[shape].update({label: vals[val_idxs]}) - else: - for shape, labels in external_labels.items(): - train_label_dict.update({shape: {}}) - for label, vals in labels.items(): - train_label_dict[shape].update({label: vals[train_idxs]}) - - return train_label_dict, val_label_dict From d6294b8082abe504a85809443224758c75350af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 12:19:34 +0100 Subject: [PATCH 026/192] adjusted md test --- tests/integration_tests/md/test_md.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/integration_tests/md/test_md.py b/tests/integration_tests/md/test_md.py index b04216d3..e34a2dbf 100644 --- a/tests/integration_tests/md/test_md.py +++ b/tests/integration_tests/md/test_md.py @@ -9,7 +9,6 @@ from ase import Atoms from ase.io import read, write from flax.training import checkpoints -from jax_md import partition, space from apax.config import Config, MDConfig from apax.md import run_md @@ -54,13 +53,13 @@ def test_run_md(get_tmp_path): n_species = 119 # int(np.max(atomic_numbers) + 1) - displacement_fn, _ = space.free() + displacement_fn, _ = jax_md_reduced.space.free() neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_or_metric=displacement_fn, box=box, r_cutoff=model_config.model.r_max, - format=partition.Sparse, + format=jax_md_reduced.partition.Sparse, fractional_coordinates=False, ) neighbors = neighbor_fn.allocate(positions) @@ -126,13 +125,13 @@ def test_ase_calc(get_tmp_path): atoms = Atoms(atomic_numbers, positions, cell=box) write(initial_structure_path.as_posix(), atoms) - displacement_fn, _ = space.periodic_general(cell_size, fractional_coordinates=False) + displacement_fn, _ = jax_md_reduced.space.periodic_general(cell_size, fractional_coordinates=False) neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_or_metric=displacement_fn, box=box, r_cutoff=model_config.model.r_max, - format=partition.Sparse, + format=jax_md_reduced.partition.Sparse, fractional_coordinates=False, ) neighbors = neighbor_fn.allocate(positions) From 59e7fbb27b7ba639ce09719df1971ba20fabdfe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 13:09:47 +0100 Subject: [PATCH 027/192] made shape of additional labels something to be specified in the input file. --- apax/bal/api.py | 2 +- apax/data/initialization.py | 42 ++++++++++++++----------- apax/data/input_pipeline.py | 63 ++----------------------------------- apax/md/ase_calc.py | 12 ++++--- apax/train/eval.py | 8 ++--- apax/train/trainer.py | 10 +++--- apax/utils/convert.py | 20 ++++++++++-- 7 files changed, 61 insertions(+), 96 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index b905c4d9..bc0eea4a 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -87,7 +87,7 @@ def kernel_selection( n_train = len(train_atoms) dataset = initialize_dataset( - config, train_atoms + pool_atoms, calc_stats=False + config, train_atoms + pool_atoms, read_labels=False, calc_stats=False ) dataset.set_batch_size(processing_batch_size) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 4615abde..1a9a110f 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -1,12 +1,10 @@ -import dataclasses import logging -from typing import Optional import numpy as np -from ase import Atoms -from apax.data.input_pipeline import AtomisticDataset, process_inputs, process_labels +from apax.data.input_pipeline import AtomisticDataset, process_inputs from apax.data.statistics import compute_scale_shift_parameters +from apax.utils.convert import atoms_to_labels from apax.utils.data import load_data, split_atoms, split_idxs log = logging.getLogger(__name__) @@ -40,21 +38,38 @@ def load_data_files(data_config): return train_atoms_list, val_atoms_list -def initialize_dataset(config, raw_ds, read_labels: list[str] = ["energy", "forces"], calc_stats: bool = True): +def initialize_dataset( + config, + atoms_list, + read_labels: bool = True, + additional_properties_info: dict[str, str] = {}, + calc_stats: bool = True, +): + if calc_stats and not read_labels: + raise ValueError( + "Cannot calculate scale/shift parameters without reading labels." + ) inputs = process_inputs( - raw_ds.atoms_list, + atoms_list, r_max=config.model.r_max, disable_pbar=config.progress_bar.disable_nl_pbar, pos_unit=config.data.pos_unit, ) - labels = process_labels( - raw_ds.atoms_list, + labels = atoms_to_labels( + atoms_list, + additional_properties_info=additional_properties_info, read_labels=read_labels, - external_labels=raw_ds.additional_labels, pos_unit=config.data.pos_unit, energy_unit=config.data.energy_unit, ) + dataset = AtomisticDataset( + inputs, + config.n_epochs, + labels=labels, + buffer_size=config.data.shuffle_buffer_size, + ) + if calc_stats: ds_stats = compute_scale_shift_parameters( inputs, @@ -64,15 +79,6 @@ def initialize_dataset(config, raw_ds, read_labels: list[str] = ["energy", "forc config.data.shift_options, config.data.scale_options, ) - - dataset = AtomisticDataset( - inputs, - config.n_epochs, - labels=labels, - buffer_size=config.data.shuffle_buffer_size, - ) - - if calc_stats: return dataset, ds_stats else: return dataset diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 1ad2e846..de890076 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -7,7 +7,7 @@ import tensorflow as tf from apax.data.preprocessing import dataset_neighborlist, prefetch_to_single_device -from apax.utils.convert import atoms_to_inputs, atoms_to_labels +from apax.utils.convert import atoms_to_inputs log = logging.getLogger(__name__) @@ -35,9 +35,7 @@ def __init__(self, max_atoms: int, max_nbrs: int) -> None: self.max_atoms = max_atoms self.max_nbrs = max_nbrs - def __call__( - self, inputs: dict, labels: dict = None - ) -> tuple[dict, dict]: + def __call__(self, inputs: dict, labels: dict = None) -> tuple[dict, dict]: """ Arguments --------- @@ -80,7 +78,6 @@ def __call__( new_inputs = r_inputs.copy() new_inputs.update(f_inputs) - if labels: r_labels = labels["ragged"] f_labels = labels["fixed"] @@ -97,42 +94,6 @@ def __call__( return new_inputs, new_labels else: return new_inputs - # for key, val in r_inputs.items(): - # if self.max_atoms is None: - # r_inputs[key] = val.to_tensor() - # elif key == "idx": - # shape = r_inputs[key].shape - # padded_shape = [shape[0], shape[1], self.max_nbrs] # batch, ij, nbrs - # elif key == "offsets": - # shape = r_inputs[key].shape - # padded_shape = [shape[0], self.max_nbrs, 3] # batch, ij, nbrs - # elif key == "numbers": - # shape = r_inputs[key].shape - # padded_shape = [shape[0], self.max_atoms] # batch, atoms - # else: - # shape = r_inputs[key].shape - # padded_shape = [shape[0], self.max_atoms, shape[2]] # batch, atoms, 3 - # r_inputs[key] = val.to_tensor(shape=padded_shape) - - # inputs = r_inputs.copy() - # inputs.update(f_inputs) - - - # if r_labels and f_labels: - # for key, val in r_labels.items(): - # if self.max_atoms is None: - # r_labels[key] = val.to_tensor() - # else: - # padded_shape = [shape[0], self.max_atoms, shape[2]] - # r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) - - # labels = r_labels.copy() - # labels.update(f_labels) - - - # return inputs, labels - # else: - # return inputs def process_inputs( @@ -155,25 +116,7 @@ def process_inputs( return inputs -def process_labels( - atoms_list: list, - read_labels, - external_labels: dict = {}, - pos_unit: str = "Ang", - energy_unit: str = "eV", -) -> tuple[dict]: - if len(read_labels) == 0: - return None - labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) - - if external_labels: - for shape, label in external_labels.items(): - labels[shape].update(label) - return labels - - -def dataset_from_dicts( - *dicts_of_arrays: Dict[str, np.ndarray]) -> tf.data.Dataset: +def dataset_from_dicts(*dicts_of_arrays: Dict[str, np.ndarray]) -> tf.data.Dataset: # tf.RaggedTensors should be created from `tf.ragged.stack` # instead of `tf.ragged.constant` for performance reasons. # See https://github.com/tensorflow/tensorflow/issues/47853 diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index ef13a998..59716027 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -2,10 +2,10 @@ from pathlib import Path from typing import Callable, Union +import ase import jax import jax.numpy as jnp import numpy as np -import ase from ase.calculators.calculator import Calculator, all_changes from ase.calculators.singlepoint import SinglePointCalculator from jax_md import partition, quantity, space @@ -231,7 +231,9 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): self.results = {k: np.array(v, dtype=np.float64) for k, v in results.items()} self.results["energy"] = self.results["energy"].item() - def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bool=False) -> list[ase.Atoms]: + def batch_eval( + self, atoms_list: list[ase.Atoms], batch_size: int = 64, silent: bool = False + ) -> list[ase.Atoms]: """Evaluate the model on a list of Atoms. This is preferable to assigning the calculator to each Atoms instance for 2 reasons: 1. Processing can be abtched, which is advantageous for larger datasets. @@ -256,7 +258,7 @@ def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bo if self.model is None: self.initialize(atoms_list[0]) dataset = initialize_dataset( - self.model_config, atoms_list, calc_stats=False + self.model_config, atoms_list, read_labels=False, calc_stats=False ) dataset.set_batch_size(batch_size) @@ -278,8 +280,8 @@ def batch_eval(self, atoms_list: list[ase.Atoms], batch_size: int=64, silent: bo ) unpadded_results = unpack_results(results, inputs) - # for the last batch, the number of structures may be less than the batch_size, - # which is why we check this explicitely + # for the last batch, the number of structures may be less + # than the batch_size, which is why we check this explicitely num_strucutres_in_batch = results["energy"].shape[0] for j in range(num_strucutres_in_batch): atoms = atoms_list[i].copy() diff --git a/apax/train/eval.py b/apax/train/eval.py index 01ee0681..8a504c2b 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -15,7 +15,7 @@ from apax.train.metrics import initialize_metrics from apax.train.run import initialize_loss_fn, setup_logging from apax.train.trainer import make_step_fns -from apax.utils.data import load_data, split_atoms, split_label +from apax.utils.data import load_data, split_atoms from apax.utils.random import seed_py_np_tf log = logging.getLogger(__name__) @@ -123,14 +123,12 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): raw_ds = load_test_data(config, model_version_path, eval_path, n_test) - test_ds, ds_stats = initialize_dataset(config, raw_ds) + test_ds = initialize_dataset(config, raw_ds, read_labels=False, calc_stats=False) _, init_box = test_ds.init_input() - builder = ModelBuilder(config.model.get_dict(), n_species=ds_stats.n_species) + builder = ModelBuilder(config.model.get_dict()) model = builder.build_energy_derivative_model( - scale=ds_stats.elemental_scale, - shift=ds_stats.elemental_shift, apply_mask=True, init_box=init_box, ) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..684203eb 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,10 +109,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index f296cd1b..3199742f 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -1,3 +1,5 @@ +from typing import Optional + import jax.numpy as jnp import numpy as np from ase import Atoms @@ -42,7 +44,7 @@ def atoms_to_inputs( atoms_list: list[Atoms], pos_unit: str = "Ang", ) -> dict[str, dict[str, list]]: - """Converts an list of ASE atoms to a dict where all inputs + """Converts an list of ASE atoms to a dict where all inputs are sorted by their shape (ragged/fixed). Units are adjusted if ASE compatible and provided in the inputpipeline. @@ -68,7 +70,7 @@ def atoms_to_inputs( "box": [], }, } - + box = atoms_list[0].cell.array pbc = np.all(box > 1e-6) @@ -106,6 +108,8 @@ def atoms_to_inputs( def atoms_to_labels( atoms_list: list[Atoms], + additional_properties_info: Optional[dict] = {}, + read_labels: bool = True, pos_unit: str = "Ang", energy_unit: str = "eV", ) -> dict[str, dict[str, list]]: @@ -122,6 +126,8 @@ def atoms_to_labels( labels : Labels are trainable system properties. """ + if not read_labels: + return None labels = { "ragged": { @@ -132,6 +138,10 @@ def atoms_to_labels( "stress": [], }, } + for key in additional_properties_info.keys(): + shape = additional_properties_info[key] + placeholder = {key: []} + labels[shape].update(placeholder) for atoms in atoms_list: for key, val in atoms.calc.results.items(): @@ -149,6 +159,10 @@ def atoms_to_labels( ) labels["fixed"][key].append(stress * atoms.cell.volume) + elif key in additional_properties_info.keys(): + shape = additional_properties_info[key] + labels[shape][key].append(atoms.calc.results[key]) + labels["fixed"] = prune_dict(labels["fixed"]) labels["ragged"] = prune_dict(labels["ragged"]) - return labels \ No newline at end of file + return labels From 6fd57df92f887e0a5f0dc57b9e4156304e44c977 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:10:33 +0000 Subject: [PATCH 028/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 684203eb..0c96277b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,12 +109,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From af3a19dcda0400f1ac539541007815143ec443db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 13:29:45 +0100 Subject: [PATCH 029/192] updated import paths in tests --- tests/unit_tests/data/test_input_pipeline.py | 46 ++++++++++---------- tests/unit_tests/data/test_statistics.py | 6 ++- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index faf33eb0..4ea463b0 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -8,10 +8,10 @@ from apax.data.input_pipeline import ( AtomisticDataset, PadToSpecificSize, - create_dict_dataset, + process_inputs, ) from apax.model.gmnn import disp_fn -from apax.utils.convert import atoms_to_arrays +from apax.utils.convert import atoms_to_labels from apax.utils.data import split_atoms, split_idxs from apax.utils.random import seed_py_np_tf @@ -26,11 +26,11 @@ 5, True, ["energy", "forces"], - { - "fixed": { - "ma_tensors": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)) - } - }, + [{ + "name": "ma_tensors", + "shape": "fixed", + "values": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)) + }], ], ), ) @@ -38,12 +38,21 @@ def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): batch_size = 2 r_max = 6.0 - inputs, labels = create_dict_dataset( + label_info = {} + if external_labels: + for l in external_labels: + label_info[l["shape"]].update(l["name"]) + label_info[l["shape"]] = l["values"] + + for a,v in zip(example_atoms, l["values"]): + a.calc.results[l["name"]] = v + + inputs = process_inputs( example_atoms, - r_max, - external_labels, + r_max=r_max, disable_pbar=True, ) + labels = atoms_to_labels(example_atoms, additional_properties_info=external_labels) ds = AtomisticDataset( inputs, @@ -157,7 +166,8 @@ def test_split_data(example_atoms): ), ) def test_convert_atoms_to_arrays(example_atoms, pbc): - inputs, labels = atoms_to_arrays(example_atoms) + inputs = process_inputs(example_atoms, r_max=6.0) + labels = atoms_to_labels(example_atoms, read_labels=True) assert "fixed" in inputs assert "ragged" in inputs @@ -185,29 +195,26 @@ def test_convert_atoms_to_arrays(example_atoms, pbc): @pytest.mark.parametrize( - "pbc, calc_results, external_labels, cell", + "pbc, calc_results, cell", ( [ True, ["energy"], - None, np.array([[1.8, 0.1, 0.0], [0.0, 2.5, 0.1], [0.1, 0.0, 2.5]]), ], [ True, ["energy"], - None, np.array([[1.8, 0.0, 0.0], [0.0, 2.5, 0.0], [0.0, 0.0, 2.5]]), ], [ True, ["energy"], - None, np.array([[1.5, 0.0, 0.5], [0.0, 2.5, 0.0], [0.0, 0.5, 1.5]]), ], ), ) -def test_neighbors_and_displacements(pbc, calc_results, external_labels, cell): +def test_neighbors_and_displacements(pbc, calc_results, cell): r_max = 2.0 numbers = np.array([1, 1]) @@ -228,12 +235,7 @@ def test_neighbors_and_displacements(pbc, calc_results, external_labels, cell): results[key] = result_shapes[key] atoms.calc = SinglePointCalculator(atoms, **results) - inputs, _ = create_dict_dataset( - [atoms], - r_max, - external_labels, - disable_pbar=True, - ) + inputs = process_inputs([atoms], r_max=r_max, disable_pbar=True) idx = np.asarray(inputs["ragged"]["idx"])[0] offsets = np.asarray(inputs["ragged"]["offsets"][0]) diff --git a/tests/unit_tests/data/test_statistics.py b/tests/unit_tests/data/test_statistics.py index 394c4148..a107e0b5 100644 --- a/tests/unit_tests/data/test_statistics.py +++ b/tests/unit_tests/data/test_statistics.py @@ -2,8 +2,9 @@ from ase import Atoms from ase.calculators.singlepoint import SinglePointCalculator -from apax.data.input_pipeline import create_dict_dataset +from apax.data.input_pipeline import process_inputs from apax.data.statistics import PerElementRegressionShift +from apax.utils.convert import atoms_to_labels def test_energy_per_element(): @@ -23,10 +24,11 @@ def test_energy_per_element(): energies.append(energy) atoms.calc = SinglePointCalculator(atoms, energy=energy) - inputs, labels = create_dict_dataset( + inputs = process_inputs( atoms_list, r_max=6.5, ) + labels = atoms_to_labels(atoms) elemental_shift = PerElementRegressionShift.compute( inputs, labels, {"energy_regularisation": 0.0} From b3a4b2098d557b951fa416213b9f36015f1cb6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 14:03:15 +0100 Subject: [PATCH 030/192] fixed tests --- apax/data/initialization.py | 16 +++++---- apax/data/input_pipeline.py | 35 ++++++++++++++------ tests/unit_tests/data/test_input_pipeline.py | 15 +++++---- tests/unit_tests/data/test_statistics.py | 2 +- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 1a9a110f..2d37debb 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -63,13 +63,6 @@ def initialize_dataset( energy_unit=config.data.energy_unit, ) - dataset = AtomisticDataset( - inputs, - config.n_epochs, - labels=labels, - buffer_size=config.data.shuffle_buffer_size, - ) - if calc_stats: ds_stats = compute_scale_shift_parameters( inputs, @@ -79,6 +72,15 @@ def initialize_dataset( config.data.shift_options, config.data.scale_options, ) + + dataset = AtomisticDataset( + inputs, + config.n_epochs, + labels=labels, + buffer_size=config.data.shuffle_buffer_size, + ) + + if calc_stats: return dataset, ds_stats else: return dataset diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index de890076..6a006ae6 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -1,5 +1,5 @@ import logging -from typing import Dict, Iterator +from typing import Dict, Iterator, Optional import jax import jax.numpy as jnp @@ -116,18 +116,29 @@ def process_inputs( return inputs -def dataset_from_dicts(*dicts_of_arrays: Dict[str, np.ndarray]) -> tf.data.Dataset: +def dataset_from_dicts( + inputs: Dict[str, np.ndarray], labels: Optional[Dict[str, np.ndarray]] = None +) -> tf.data.Dataset: # tf.RaggedTensors should be created from `tf.ragged.stack` # instead of `tf.ragged.constant` for performance reasons. # See https://github.com/tensorflow/tensorflow/issues/47853 - for doa in dicts_of_arrays: - for key, val in doa["ragged"].items(): - doa["ragged"][key] = tf.ragged.stack(val) - for key, val in doa["fixed"].items(): - doa["fixed"][key] = tf.constant(val) - - # add check for more than 2 datasets - ds = tf.data.Dataset.from_tensor_slices(*dicts_of_arrays) + for key, val in inputs["ragged"].items(): + inputs["ragged"][key] = tf.ragged.stack(val) + for key, val in inputs["fixed"].items(): + inputs["fixed"][key] = tf.constant(val) + + if labels: + for key, val in labels["ragged"].items(): + labels["ragged"][key] = tf.ragged.stack(val) + for key, val in labels["fixed"].items(): + labels["fixed"][key] = tf.constant(val) + + tensors = (inputs, labels) + else: + tensors = inputs + + ds = tf.data.Dataset.from_tensor_slices(tensors) + return ds @@ -205,12 +216,14 @@ def steps_per_epoch(self) -> int: def init_input(self) -> Dict[str, np.ndarray]: """Returns first batch of inputs and labels to init the model.""" - inputs, _ = next( + inputs = next( self.ds.batch(1) .map(PadToSpecificSize(self.max_atoms, self.max_nbrs)) .take(1) .as_numpy_iterator() ) + if isinstance(inputs, tuple): + inputs = inputs[0] # remove labels inputs = jax.tree_map(lambda x: jnp.array(x[0]), inputs) init_box = np.array(inputs["box"]) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 4ea463b0..370065e4 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -38,26 +38,27 @@ def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): batch_size = 2 r_max = 6.0 - label_info = {} if external_labels: + label_info = {} for l in external_labels: - label_info[l["shape"]].update(l["name"]) - label_info[l["shape"]] = l["values"] + label_info[l["name"]] = l["shape"] for a,v in zip(example_atoms, l["values"]): a.calc.results[l["name"]] = v + else: + label_info = {} inputs = process_inputs( example_atoms, r_max=r_max, disable_pbar=True, ) - labels = atoms_to_labels(example_atoms, additional_properties_info=external_labels) + labels = atoms_to_labels(example_atoms, additional_properties_info=label_info) ds = AtomisticDataset( inputs, - labels, 1, + labels=labels, buffer_size=1000, ) ds.set_batch_size(batch_size) @@ -112,13 +113,15 @@ def test_pad_to_specific_size(): f_2 = [[3.0, 3.0, 3.0], [3.0, 3.0, 3.0], [3.0, 3.0, 3.0]] r_lab = {"forces": tf.ragged.constant([f_1, f_2])} p_lab = {"energy": tf.constant([103.3, 98.4])} + inputs = {"fixed": p_inp, "ragged": r_inp} + labels = {"fixed": p_lab, "ragged": r_lab} max_atoms = 5 max_nbrs = 6 padding_fn = PadToSpecificSize(max_atoms=max_atoms, max_nbrs=max_nbrs) - inputs, labels = padding_fn(r_inp, p_inp, r_lab, p_lab) + inputs, labels = padding_fn(inputs, labels) assert "idx" in inputs assert inputs["idx"].shape == [2, 2, 6] diff --git a/tests/unit_tests/data/test_statistics.py b/tests/unit_tests/data/test_statistics.py index a107e0b5..6ae80c90 100644 --- a/tests/unit_tests/data/test_statistics.py +++ b/tests/unit_tests/data/test_statistics.py @@ -28,7 +28,7 @@ def test_energy_per_element(): atoms_list, r_max=6.5, ) - labels = atoms_to_labels(atoms) + labels = atoms_to_labels(atoms_list) elemental_shift = PerElementRegressionShift.compute( inputs, labels, {"energy_regularisation": 0.0} From 0f8694a2706a23a794a2f615d30e10c277e34baf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:05:48 +0000 Subject: [PATCH 031/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/unit_tests/data/test_input_pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 370065e4..63cb78db 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -29,7 +29,7 @@ [{ "name": "ma_tensors", "shape": "fixed", - "values": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)) + "values": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)), }], ], ), @@ -43,7 +43,7 @@ def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): for l in external_labels: label_info[l["name"]] = l["shape"] - for a,v in zip(example_atoms, l["values"]): + for a, v in zip(example_atoms, l["values"]): a.calc.results[l["name"]] = v else: label_info = {} From 554f850a0ad95eadd078c6138c21fc1c54e28000 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:08:48 +0000 Subject: [PATCH 032/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/unit_tests/data/test_input_pipeline.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 63cb78db..57cb36e1 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -5,11 +5,7 @@ from ase.calculators.singlepoint import SinglePointCalculator from jax import vmap -from apax.data.input_pipeline import ( - AtomisticDataset, - PadToSpecificSize, - process_inputs, -) +from apax.data.input_pipeline import AtomisticDataset, PadToSpecificSize, process_inputs from apax.model.gmnn import disp_fn from apax.utils.convert import atoms_to_labels from apax.utils.data import split_atoms, split_idxs From 3af1be96c15576ab68f5fcb54e24ef0c89e126c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 14:10:52 +0100 Subject: [PATCH 033/192] linting --- tests/unit_tests/data/test_input_pipeline.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 57cb36e1..7ab1728b 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -36,11 +36,11 @@ def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): if external_labels: label_info = {} - for l in external_labels: - label_info[l["name"]] = l["shape"] + for label in external_labels: + label_info[label["name"]] = label["shape"] - for a, v in zip(example_atoms, l["values"]): - a.calc.results[l["name"]] = v + for a, v in zip(example_atoms, label["values"]): + a.calc.results[label["name"]] = v else: label_info = {} From a514913031979925143612549a6e8df0eed7edec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 15:37:47 +0100 Subject: [PATCH 034/192] completed removal of space --- apax/utils/jax_md_reduced/README.md | 1 - apax/utils/jax_md_reduced/dataclasses.py | 79 ++++ apax/utils/jax_md_reduced/partition.py | 488 ++++++++++++++++++++--- apax/utils/jax_md_reduced/quantity.py | 13 + apax/utils/jax_md_reduced/simulate.py | 13 + apax/utils/jax_md_reduced/space.py | 84 ++++ apax/utils/jax_md_reduced/util.py | 33 ++ 7 files changed, 649 insertions(+), 62 deletions(-) create mode 100644 apax/utils/jax_md_reduced/dataclasses.py diff --git a/apax/utils/jax_md_reduced/README.md b/apax/utils/jax_md_reduced/README.md index 24798364..99983b75 100644 --- a/apax/utils/jax_md_reduced/README.md +++ b/apax/utils/jax_md_reduced/README.md @@ -3,7 +3,6 @@ apax relies on the amazing `jax_md` package for neighborlists and thermostats. Some of our use cases run into bugs in functionality provided by `jax_md`. Hence, this submodule contains a small number of fixes for some `jax_md` features. -We will switch over to the official implementations for any bug fixed upstream. We would like to thank the developers of `jax_md` for the work on this great package. diff --git a/apax/utils/jax_md_reduced/dataclasses.py b/apax/utils/jax_md_reduced/dataclasses.py new file mode 100644 index 00000000..f70790dc --- /dev/null +++ b/apax/utils/jax_md_reduced/dataclasses.py @@ -0,0 +1,79 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilities for defining dataclasses that can be used with jax transformations. + +This code was copied and adapted from https://github.com/google/flax/struct.py. + +Accessed on 04/29/2020. +""" + +import dataclasses +import jax + + +def dataclass(clz): + """Create a class which can be passed to functional transformations. + + Jax transformations such as `jax.jit` and `jax.grad` require objects that are + immutable and can be mapped over using the `jax.tree_util` methods. + + The `dataclass` decorator makes it easy to define custom classes that can be + passed safely to Jax. + + Args: + clz: the class that will be transformed by the decorator. + Returns: + The new class. + """ + clz.set = lambda self, **kwargs: dataclasses.replace(self, **kwargs) + data_clz = dataclasses.dataclass(frozen=True)(clz) + meta_fields = [] + data_fields = [] + for name, field_info in data_clz.__dataclass_fields__.items(): + is_static = field_info.metadata.get('static', False) + if is_static: + meta_fields.append(name) + else: + data_fields.append(name) + + def iterate_clz(x): + meta = tuple(getattr(x, name) for name in meta_fields) + data = tuple(getattr(x, name) for name in data_fields) + return data, meta + + def clz_from_iterable(meta, data): + meta_args = tuple(zip(meta_fields, meta)) + data_args = tuple(zip(data_fields, data)) + kwargs = dict(meta_args + data_args) + return data_clz(**kwargs) + + jax.tree_util.register_pytree_node(data_clz, + iterate_clz, + clz_from_iterable) + + return data_clz + + +def static_field(): + return dataclasses.field(metadata={'static': True}) + +replace = dataclasses.replace +asdict = dataclasses.asdict +astuple = dataclasses.astuple +is_dataclass = dataclasses.is_dataclass +fields = dataclasses.fields +field = dataclasses.field +def unpack(dc) -> tuple: + return tuple(getattr(dc, field.name) for field in dataclasses.fields(dc)) diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 870dd7f5..3f9a79d4 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -1,28 +1,27 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from functools import partial -from typing import Any, Callable, Optional +import logging +from typing import Any, Callable, Optional, Dict, Generator import jax.numpy as jnp import numpy as onp -from jax import jit, lax, vmap -from jax_md import dataclasses, space, util -from jax_md.partition import ( - PEC, - CellList, - NeighborFn, - NeighborList, - NeighborListFns, - NeighborListFormat, - PartitionError, - _cell_size, - _displacement_or_metric_to_metric_sq, - _fractional_cell_size, - _neighboring_cells, - _shift_array, - cell_list, - is_box_valid, - is_format_valid, - is_sparse, -) +from jax.core import ShapedArray +from jax import jit, vmap, eval_shape, lax +from enum import IntEnum ,Enum +from apax.utils.jax_md_reduced import util, space, dataclasses Array = util.Array PyTree = Any @@ -37,11 +36,377 @@ MetricFn = space.MetricFn MaskFn = Callable[[Array], Array] + +def _cell_size(box, minimum_cell_size) -> Array: + cells_per_side = jnp.floor(box / minimum_cell_size) + return box / cells_per_side + + +def _fractional_cell_size(box, cutoff): + if jnp.isscalar(box) or box.ndim == 0: + return cutoff / box + elif box.ndim == 1: + return cutoff / jnp.min(box) + elif box.ndim == 2: + if box.shape[0] == 1: + return 1 / jnp.floor(box[0, 0] / cutoff) + elif box.shape[0] == 2: + xx = box[0, 0] + yy = box[1, 1] + xy = box[0, 1] / yy + + nx = xx / jnp.sqrt(1 + xy**2) + ny = yy + + nmin = jnp.floor(jnp.min(jnp.array([nx, ny])) / cutoff) + nmin = jnp.where(nmin == 0, 1, nmin) + return 1 / nmin + elif box.shape[0] == 3: + xx = box[0, 0] + yy = box[1, 1] + zz = box[2, 2] + xy = box[0, 1] / yy + xz = box[0, 2] / zz + yz = box[1, 2] / zz + + nx = xx / jnp.sqrt(1 + xy**2 + (xy * yz - xz)**2) + ny = yy / jnp.sqrt(1 + yz**2) + nz = zz + + nmin = jnp.floor(jnp.min(jnp.array([nx, ny, nz])) / cutoff) + nmin = jnp.where(nmin == 0, 1, nmin) + return 1 / nmin + else: + raise ValueError('Expected box to be either 1-, 2-, or 3-dimensional ' + f'found {box.shape[0]}') + else: + raise ValueError('Expected box to be either a scalar, a vector, or a ' + f'matrix. Found {type(box)}.') + +def _displacement_or_metric_to_metric_sq( + displacement_or_metric: DisplacementOrMetricFn) -> MetricFn: + """Checks whether or not a displacement or metric was provided.""" + for dim in range(1, 4): + try: + R = ShapedArray((dim,), f32) + dR_or_dr = eval_shape(displacement_or_metric, R, R, t=0) + if len(dR_or_dr.shape) == 0: + return lambda Ra, Rb, **kwargs: \ + displacement_or_metric(Ra, Rb, **kwargs) ** 2 + else: + return lambda Ra, Rb, **kwargs: space.square_distance( + displacement_or_metric(Ra, Rb, **kwargs)) + except TypeError: + continue + except ValueError: + continue + raise ValueError( + 'Canonicalize displacement not implemented for spatial dimension larger' + 'than 4.') + +# Neighbor Lists + + +@dataclasses.dataclass +class CellList: + """Stores the spatial partition of a system into a cell list. + + See :meth:`cell_list` for details on the construction / specification. + Cell list buffers all have a common shape, S, where + * `S = [cell_count_x, cell_count_y, cell_capacity]` + * `S = [cell_count_x, cell_count_y, cell_count_z, cell_capacity]` + in two- and three-dimensions respectively. It is assumed that each cell has + the same capacity. + + Attributes: + position_buffer: An ndarray of floating point positions with shape + `S + [spatial_dimension]`. + id_buffer: An ndarray of int32 particle ids of shape `S`. Note that empty + slots are specified by `id = N` where `N` is the number of particles in + the system. + named_buffer: A dictionary of ndarrays of shape `S + [...]`. This contains + side data placed into the cell list. + did_buffer_overflow: A boolean specifying whether or not the cell list + exceeded the maximum allocated capacity. + cell_capacity: An integer specifying the maximum capacity of each cell in + the cell list. + update_fn: A function that updates the cell list at a fixed capacity. + """ + position_buffer: Array + id_buffer: Array + named_buffer: Dict[str, Array] + + did_buffer_overflow: Array + + cell_capacity: int = dataclasses.static_field() + cell_size: float = dataclasses.static_field() + + update_fn: Callable[..., 'CellList'] = \ + dataclasses.static_field() + + def update(self, position: Array, **kwargs) -> 'CellList': + cl_data = (self.cell_capacity, self.did_buffer_overflow, self.update_fn) + return self.update_fn(position, cl_data, **kwargs) + + @property + def kwarg_buffers(self): + logging.warning('kwarg_buffers renamed to named_buffer. The name ' + 'kwarg_buffers will be depricated.') + return self.named_buffer + +class NeighborListFormat(Enum): + """An enum listing the different neighbor list formats. + + Attributes: + Dense: A dense neighbor list where the ids are a square matrix + of shape `(N, max_neighbors_per_atom)`. Here the capacity of the neighbor + list must scale with the highest connectivity neighbor. + Sparse: A sparse neighbor list where the ids are a rectangular + matrix of shape `(2, max_neighbors)` specifying the start / end particle + of each neighbor pair. + OrderedSparse: A sparse neighbor list whose format is the same as `Sparse` + where only bonds with i < j are included. + """ + Dense = 0 + Sparse = 1 + OrderedSparse = 2 + +class PartitionErrorCode(IntEnum): + """An enum specifying different error codes. + + Attributes: + NONE: Means that no error was encountered during simulation. + NEIGHBOR_LIST_OVERFLOW: Indicates that the neighbor list was not large + enough to contain all of the particles. This should indicate that it is + necessary to allocate a new neighbor list. + CELL_LIST_OVERFLOW: Indicates that the cell list was not large enough to + contain all of the particles. This should indicate that it is necessary + to allocate a new cell list. + CELL_SIZE_TOO_SMALL: Indicates that the size of cells in a cell list was + not large enough to properly capture particle interactions. This + indicates that it is necessary to allcoate a new cell list with larger + cells. + MALFORMED_BOX: Indicates that a box matrix was not properly upper + triangular. + """ + NONE = 0 + NEIGHBOR_LIST_OVERFLOW = 1 << 0 + CELL_LIST_OVERFLOW = 1 << 1 + CELL_SIZE_TOO_SMALL = 1 << 2 + MALFORMED_BOX = 1 << 3 +PEC = PartitionErrorCode + + +@dataclasses.dataclass +class PartitionError: + """A struct containing error codes while building / updating neighbor lists. + + Attributes: + code: An array storing the error code. See `PartitionErrorCode` for + details. + """ + code: Array + + def update(self, bit: bytes, pred: Array) -> Array: + """Possibly adds an error based on a predicate.""" + zero = jnp.zeros((), jnp.uint8) + bit = jnp.array(bit, dtype=jnp.uint8) + return PartitionError(self.code | jnp.where(pred, bit, zero)) + + def __str__(self) -> str: + """Produces a string representation of the error code.""" + if not jnp.any(self.code): + return '' + + if jnp.any(self.code & PEC.NEIGHBOR_LIST_OVERFLOW): + return 'Partition Error: Neighbor list buffer overflow.' + + if jnp.any(self.code & PEC.CELL_LIST_OVERFLOW): + return 'Partition Error: Cell list buffer overflow' + + if jnp.any(self.code & PEC.CELL_SIZE_TOO_SMALL): + return 'Partition Error: Cell size too small' + + if jnp.any(self.code & PEC.MALFORMED_BOX): + return ('Partition Error: Incorrect box format. Expecting upper ' + 'triangular.') + + raise ValueError(f'Unexpected Error Code {self.code}.') + + __repr__ = __str__ + +@dataclasses.dataclass +class NeighborList: + """A struct containing the state of a Neighbor List. + + Attributes: + idx: For an N particle system this is an `[N, max_occupancy]` array of + integers such that `idx[i, j]` is the j-th neighbor of particle i. + reference_position: The positions of particles when the neighbor list was + constructed. This is used to decide whether the neighbor list ought to be + updated. + error: An error code that is used to identify errors that occured during + neighbor list construction. See `PartitionError` and `PartitionErrorCode` + for details. + cell_list_capacity: An optional integer specifying the capacity of the cell + list used as an intermediate step in the creation of the neighbor list. + max_occupancy: A static integer specifying the maximum size of the + neighbor list. Changing this will invoke a recompilation. + format: A NeighborListFormat enum specifying the format of the neighbor + list. + cell_size: A float specifying the current minimum size of the cells used + in cell list construction. + cell_list_fn: The function used to construct the cell list. + update_fn: A static python function used to update the neighbor list. + """ + idx: Array + reference_position: Array + error: PartitionError + cell_list_capacity: Optional[int] = dataclasses.static_field() + max_occupancy: int = dataclasses.static_field() + + format: NeighborListFormat = dataclasses.static_field() + cell_size: Optional[float] = dataclasses.static_field() + cell_list_fn: Callable[[Array, CellList], + CellList] = dataclasses.static_field() + update_fn: Callable[[Array, 'NeighborList'], + 'NeighborList'] = dataclasses.static_field() + + def update(self, position: Array, **kwargs) -> 'NeighborList': + return self.update_fn(position, self, **kwargs) + + @property + def did_buffer_overflow(self) -> bool: + return self.error.code & (PEC.NEIGHBOR_LIST_OVERFLOW | + PEC.CELL_LIST_OVERFLOW) + + @property + def cell_size_too_small(self) -> bool: + return self.error.code & PEC.CELL_SIZE_TOO_SMALL + + @property + def malformed_box(self) -> bool: + return self.error.code & PEC.MALFORMED_BOX + +def is_sparse(fmt: NeighborListFormat) -> bool: + return (fmt is NeighborListFormat.Sparse or + fmt is NeighborListFormat.OrderedSparse) + + +def is_format_valid(fmt: NeighborListFormat): + if fmt not in list(NeighborListFormat): + raise ValueError(( + 'Neighbor list format must be a member of NeighborListFormat' + f' found {fmt}.')) + + +def is_box_valid(box: Array) -> bool: + if jnp.isscalar(box) or box.ndim == 0 or box.ndim == 1: + return True + if box.ndim == 2: + return jnp.triu(box) == box + return False + + +@dataclasses.dataclass +class NeighborListFns: + """A struct containing functions to allocate and update neighbor lists. + + Attributes: + allocate: A function to allocate a new neighbor list. This function cannot + be compiled, since it uses the values of positions to infer the shapes. + update: A function to update a neighbor list given a new set of positions + and a previously allocated neighbor list. + """ + allocate: Callable[..., NeighborList] = dataclasses.static_field() + update: Callable[[Array, NeighborList], + NeighborList] = dataclasses.static_field() + + def __call__(self, + position: Array, + neighbors: Optional[NeighborList] = None, + extra_capacity: int = 0, + **kwargs) -> NeighborList: + """A function for backward compatibility with previous neighbor lists. + + Args: + position: An `(N, dim)` array of particle positions. + neighbors: An optional neighbor list object. If it is provided then + the function updates the neighbor list, otherwise it allocates a new + neighbor list. + extra_capacity: Extra capacity to add if allocating the neighbor list. + Returns: + A neighbor list object. + """ + logging.warning('Using a deprecated code path to create / update neighbor ' + 'lists. It will be removed in a later version of JAX MD. ' + 'Using `neighbor_fn.allocate` and `neighbor_fn.update` ' + 'is preferred.') + if neighbors is None: + return self.allocate(position, extra_capacity, **kwargs) + return self.update(position, neighbors, **kwargs) + + def __iter__(self): + return iter((self.allocate, self.update)) + NeighborFn = Callable[[Array, Optional[NeighborList], Optional[int]], NeighborList] Sparse = NeighborListFormat.Sparse + + + + +# def cell_list(box_size: Box, +# minimum_cell_size: float, +# buffer_size_multiplier: float = 1.25 +# ): +# r"""Returns a function that partitions point data spatially. + +# Given a set of points :math:`\{x_i \in R^d\}` with associated data +# :math:`\{k_i \in R^m\}` it is often useful to partition the points / data +# spatially. A simple partitioning that can be implemented efficiently within +# XLA is a dense partition into a uniform grid called a cell list. + +# Since XLA requires that shapes be statically specified inside of a JIT block, +# the cell list code can operate in two modes: allocation and update. + +# Allocation creates a new cell list that uses a set of input positions to +# estimate the capacity of the cell list. This capacity can be adjusted by +# setting the `buffer_size_multiplier` or setting the `extra_capacity`. +# Allocation cannot be JIT. + +# Updating takes a previously allocated cell list and places a new set of +# particles in the cells. Updating cannot resize the cell list and is therefore +# compatible with JIT. However, if the configuration has changed substantially +# it is possible that the existing cell list won't be large enough to +# accommodate all of the particles. In this case the `did_buffer_overflow` bit +# will be set to True. + +# Args: +# box_size: A float or an ndarray of shape `[spatial_dimension]` specifying +# the size of the system. Note, this code is written for the case where the +# boundaries are periodic. If this is not the case, then the current code +# will be slightly less efficient. +# minimum_cell_size: A float specifying the minimum side length of each cell. +# Cells are enlarged so that they exactly fill the box. +# buffer_size_multiplier: A floating point multiplier that multiplies the +# estimated cell capacity to allow for fluctuations in the maximum cell +# occupancy. +# Returns: +# A `CellListFns` object that contains two methods, one to allocate the cell +# list and one to update the cell list. The update function can be called +# with either a cell list from which the capacity can be inferred or with +# an explicit integer denoting the capacity. Note that an existing cell list +# can also be updated by calling `cell_list.update(position)`. +# """ + +# return None #CellListFns(allocate_fn, update_fn) # pytype: disable=wrong-arg-count + + + + def neighbor_list( displacement_or_metric: DisplacementOrMetricFn, box: Box, @@ -150,31 +515,31 @@ def candidate_fn(position: Array) -> Array: candidates[None, :], (position.shape[0], position.shape[0]) ) - @jit - def cell_list_candidate_fn(cl: CellList, position: Array) -> Array: - N, dim = position.shape + # @jit + # def cell_list_candidate_fn(cl: CellList, position: Array) -> Array: + # N, dim = position.shape - idx = cl.id_buffer + # idx = cl.id_buffer - cell_idx = [idx] + # cell_idx = [idx] - for dindex in _neighboring_cells(dim): - if onp.all(dindex == 0): - continue - cell_idx += [_shift_array(idx, dindex)] + # for dindex in _neighboring_cells(dim): + # if onp.all(dindex == 0): + # continue + # cell_idx += [_shift_array(idx, dindex)] - cell_idx = jnp.concatenate(cell_idx, axis=-2) - cell_idx = cell_idx[..., jnp.newaxis, :, :] - cell_idx = jnp.broadcast_to(cell_idx, idx.shape[:-1] + cell_idx.shape[-2:]) + # cell_idx = jnp.concatenate(cell_idx, axis=-2) + # cell_idx = cell_idx[..., jnp.newaxis, :, :] + # cell_idx = jnp.broadcast_to(cell_idx, idx.shape[:-1] + cell_idx.shape[-2:]) - def copy_values_from_cell(value, cell_value, cell_id): - scatter_indices = jnp.reshape(cell_id, (-1,)) - cell_value = jnp.reshape(cell_value, (-1,) + cell_value.shape[-2:]) - return value.at[scatter_indices].set(cell_value) + # def copy_values_from_cell(value, cell_value, cell_id): + # scatter_indices = jnp.reshape(cell_id, (-1,)) + # cell_value = jnp.reshape(cell_value, (-1,) + cell_value.shape[-2:]) + # return value.at[scatter_indices].set(cell_value) - neighbor_idx = jnp.zeros((N + 1,) + cell_idx.shape[-2:], i32) - neighbor_idx = copy_values_from_cell(neighbor_idx, cell_idx, idx) - return neighbor_idx[:-1, :, 0] + # neighbor_idx = jnp.zeros((N + 1,) + cell_idx.shape[-2:], i32) + # neighbor_idx = copy_values_from_cell(neighbor_idx, cell_idx, idx) + # return neighbor_idx[:-1, :, 0] @jit def mask_self_fn(idx: Array) -> Array: @@ -239,31 +604,32 @@ def neighbor_fn(position_and_error, max_occupancy=None): cl_fn = None cl = None - cell_size = None - if not disable_cell_list: - if neighbors is None: - _box = kwargs.get("box", box) - cell_size = cutoff - if fractional_coordinates: - err = err.update(PEC.MALFORMED_BOX, is_box_valid(_box)) - cell_size = _fractional_cell_size(_box, cutoff) - _box = 1.0 - if jnp.all(cell_size < _box / 3.0): - cl_fn = cell_list(_box, cell_size, capacity_multiplier) - cl = cl_fn.allocate(position, extra_capacity=extra_capacity) - else: - cell_size = neighbors.cell_size - cl_fn = neighbors.cell_list_fn - if cl_fn is not None: - cl = cl_fn.update(position, neighbors.cell_list_capacity) + # cell_size = None + # if not disable_cell_list: + # if neighbors is None: + # _box = kwargs.get("box", box) + # cell_size = cutoff + # if fractional_coordinates: + # err = err.update(PEC.MALFORMED_BOX, is_box_valid(_box)) + # cell_size = _fractional_cell_size(_box, cutoff) + # _box = 1.0 + # if jnp.all(cell_size < _box / 3.0): + # cl_fn = cell_list(_box, cell_size, capacity_multiplier) + # cl = cl_fn.allocate(position, extra_capacity=extra_capacity) + # else: + # cell_size = neighbors.cell_size + # cl_fn = neighbors.cell_list_fn + # if cl_fn is not None: + # cl = cl_fn.update(position, neighbors.cell_list_capacity) if cl is None: cl_capacity = None idx = candidate_fn(position) else: - err = err.update(PEC.CELL_LIST_OVERFLOW, cl.did_buffer_overflow) - idx = cell_list_candidate_fn(cl, position) - cl_capacity = cl.cell_capacity + raise NotImplementedError("Cell lists not implemented in apax' reduced jaxmd") + # err = err.update(PEC.CELL_LIST_OVERFLOW, cl.did_buffer_overflow) + # idx = cell_list_candidate_fn(cl, position) + # cl_capacity = cl.cell_capacity if mask_self: idx = mask_self_fn(idx) @@ -299,7 +665,7 @@ def neighbor_fn(position_and_error, max_occupancy=None): cl_capacity, max_occupancy, format, - cell_size, + 0, # cell_size cl_fn, update_fn, ) # pytype: disable=wrong-arg-count diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py index e69de29b..af78543e 100644 --- a/apax/utils/jax_md_reduced/quantity.py +++ b/apax/utils/jax_md_reduced/quantity.py @@ -0,0 +1,13 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index e69de29b..af78543e 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -0,0 +1,13 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py index 040ec155..7882d6fb 100644 --- a/apax/utils/jax_md_reduced/space.py +++ b/apax/utils/jax_md_reduced/space.py @@ -1,3 +1,59 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable, Union, Tuple, Any, Optional + +from jax import custom_jvp + +import jax.numpy as jnp + +from apax.utils.jax_md_reduced.util import Array +from apax.utils.jax_md_reduced.util import f32 +from apax.utils.jax_md_reduced.util import f64 +from apax.utils.jax_md_reduced.util import safe_mask + + +# Types + + +DisplacementFn = Callable[[Array, Array], Array] +MetricFn = Callable[[Array, Array], float] +DisplacementOrMetricFn = Union[DisplacementFn, MetricFn] + +ShiftFn = Callable[[Array, Array], Array] + +Space = Tuple[DisplacementFn, ShiftFn] +Box = Array + +# Primitive Spatial Transforms + + +def inverse(box: Box) -> Box: + """Compute the inverse of an affine transformation.""" + if jnp.isscalar(box) or box.size == 1: + return 1 / box + elif box.ndim == 1: + return 1 / box + elif box.ndim == 2: + return jnp.linalg.inv(box) + raise ValueError(('Box must be either: a scalar, a vector, or a matrix. ' + f'Found {box}.')) + + +def _get_free_indices(n: int) -> str: + return ''.join([chr(ord('a') + i) for i in range(n)]) + def raw_transform(box: Box, R: Array) -> Array: """Apply an affine transformation to positions. @@ -68,6 +124,10 @@ def pairwise_displacement(Ra: Array, Rb: Array) -> Array: return Ra - Rb +def periodic_shift(side: Box, R: Array, dR: Array) -> Array: + """Shifts positions, wrapping them back within a periodic hypercube.""" + return jnp.mod(R + dR, side) + def free() -> Space: """Free boundary conditions.""" def displacement_fn(Ra: Array, Rb: Array, perturbation: Optional[Array]=None, @@ -81,6 +141,30 @@ def shift_fn(R: Array, dR: Array, **unused_kwargs) -> Array: return displacement_fn, shift_fn +def periodic_displacement(side: Box, dR: Array) -> Array: + """Wraps displacement vectors into a hypercube. + + Args: + side: Specification of hypercube size. Either, + (a) float if all sides have equal length. + (b) ndarray(spatial_dim) if sides have different lengths. + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of wrapped displacements; `ndarray(shape=[..., spatial_dim])`. + """ + return jnp.mod(dR + side * f32(0.5), side) - f32(0.5) * side + +def square_distance(dR: Array) -> Array: + """Computes square distances. + + Args: + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of squared distances; `ndarray(shape=[...])`. + """ + return jnp.sum(dR ** 2, axis=-1) + + def periodic_general(box: Box, fractional_coordinates: bool=True, wrapped: bool=True) -> Space: diff --git a/apax/utils/jax_md_reduced/util.py b/apax/utils/jax_md_reduced/util.py index e69de29b..abd25d26 100644 --- a/apax/utils/jax_md_reduced/util.py +++ b/apax/utils/jax_md_reduced/util.py @@ -0,0 +1,33 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import jax.numpy as jnp +from typing import Any +from jax import jit +from functools import partial + +Array = jnp.ndarray +PyTree = Any + +i16 = jnp.int16 +i32 = jnp.int32 +i64 = jnp.int64 + +f32 = jnp.float32 +f64 = jnp.float64 + +@partial(jit, static_argnums=(1,)) +def safe_mask(mask, fn, operand, placeholder=0): + masked = jnp.where(mask, operand, 0) + return jnp.where(mask, fn(masked), placeholder) \ No newline at end of file From f6b454152d83b302418915d13b641c8e7900be8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 15:51:32 +0100 Subject: [PATCH 035/192] added additional property options to config --- apax/config/train_config.py | 3 +++ apax/data/initialization.py | 3 +-- apax/train/trainer.py | 10 ++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index d32a58be..350849d0 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -42,6 +42,8 @@ class DataConfig(BaseModel, extra="forbid"): batch_size: Number of training examples to be evaluated at once. valid_batch_size: Number of validation examples to be evaluated at once. shuffle_buffer_size: Size of the `tf.data` shuffle buffer. + additional_properties_info: + dict of property name, shape (ragged or fixed) pairs energy_regularisation: Magnitude of the regularization in the per-element energy regression. """ @@ -58,6 +60,7 @@ class DataConfig(BaseModel, extra="forbid"): batch_size: PositiveInt = 32 valid_batch_size: PositiveInt = 100 shuffle_buffer_size: PositiveInt = 1000 + additional_properties_info: dict[str, str] = {} shift_method: str = "per_element_regression_shift" shift_options: dict = {"energy_regularisation": 1.0} diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 2d37debb..68aa59f3 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -42,7 +42,6 @@ def initialize_dataset( config, atoms_list, read_labels: bool = True, - additional_properties_info: dict[str, str] = {}, calc_stats: bool = True, ): if calc_stats and not read_labels: @@ -57,7 +56,7 @@ def initialize_dataset( ) labels = atoms_to_labels( atoms_list, - additional_properties_info=additional_properties_info, + additional_properties_info=config.data.additional_properties_info, read_labels=read_labels, pos_unit=config.data.pos_unit, energy_unit=config.data.energy_unit, diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..684203eb 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,10 +109,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From 9db40cbdf3c4d6aa7ea068153d23ff1b73ae2042 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:52:13 +0000 Subject: [PATCH 036/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 684203eb..0c96277b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,12 +109,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 5d1b584c6160e4955c82200922c28dfa0b0b5b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:10:08 +0100 Subject: [PATCH 037/192] added remaining modules, fixed all import errors --- apax/data/input_pipeline.py | 14 +- apax/md/ase_calc.py | 14 +- apax/md/nvt.py | 2 +- apax/model/gmnn.py | 20 +- apax/train/trainer.py | 10 +- apax/utils/jax_md_reduced/__init__.py | 12 +- apax/utils/jax_md_reduced/dataclasses.py | 83 +- apax/utils/jax_md_reduced/partition.py | 621 ++++---- apax/utils/jax_md_reduced/quantity.py | 735 +++++++++- apax/utils/jax_md_reduced/simulate.py | 1684 +++++++++++++++++++++- apax/utils/jax_md_reduced/smap.py | 933 ++++++++++++ apax/utils/jax_md_reduced/space.py | 505 +++---- apax/utils/jax_md_reduced/util.py | 77 +- 13 files changed, 4119 insertions(+), 591 deletions(-) create mode 100644 apax/utils/jax_md_reduced/smap.py diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 6832c587..3e53fa33 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -134,12 +134,14 @@ def dataset_from_dicts( for key, val in labels["fixed"].items(): labels["fixed"][key] = tf.constant(val) - ds = tf.data.Dataset.from_tensor_slices(( - inputs["ragged"], - inputs["fixed"], - labels["ragged"], - labels["fixed"], - )) + ds = tf.data.Dataset.from_tensor_slices( + ( + inputs["ragged"], + inputs["fixed"], + labels["ragged"], + labels["fixed"], + ) + ) return ds diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 87cf9bde..9700d9e4 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -6,11 +6,11 @@ import jax.numpy as jnp import numpy as np from ase.calculators.calculator import Calculator, all_changes -from jax_md import quantity from matscipy.neighbours import neighbour_list from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters +from apax.utils.jax_md_reduced import quantity from apax.utils import jax_md_reduced @@ -39,7 +39,9 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ if np.all(box < 1e-6): displacement_fn, _ = jax_md_reduced.space.free() else: - displacement_fn, _ = jax_md_reduced.space.periodic_general(box, fractional_coordinates=True) + displacement_fn, _ = jax_md_reduced.space.periodic_general( + box, fractional_coordinates=True + ) neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_fn, @@ -154,7 +156,9 @@ def initialize(self, atoms): positions = jnp.asarray(atoms.positions, dtype=jnp.float64) box = atoms.cell.array.T inv_box = jnp.linalg.inv(box) - positions = jax_md_reduced.space.transform(inv_box, positions) # frac coords + positions = jax_md_reduced.space.transform( + inv_box, positions + ) # frac coords self.neighbors = self.neighbor_fn.allocate(positions, box=box) else: self.neighbors = self.neighbor_fn.allocate(positions) @@ -209,7 +213,9 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): else: self.set_neighbours_and_offsets(atoms, box) - positions = np.array(jax_md_reduced.space.transform(np.linalg.inv(box), atoms.positions)) + positions = np.array( + jax_md_reduced.space.transform(np.linalg.inv(box), atoms.positions) + ) results = self.step(positions, self.neighbors, box, self.offsets) diff --git a/apax/md/nvt.py b/apax/md/nvt.py index 8c132347..7a16e452 100644 --- a/apax/md/nvt.py +++ b/apax/md/nvt.py @@ -10,7 +10,6 @@ from ase.io import read from flax.training import checkpoints from jax.experimental.host_callback import barrier_wait, id_tap -from jax_md import quantity, simulate from tqdm import trange from tqdm.contrib.logging import logging_redirect_tqdm @@ -25,6 +24,7 @@ ) from apax.train.run import setup_logging from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import quantity, simulate log = logging.getLogger(__name__) diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index 2e924409..70a7f73c 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -16,24 +16,24 @@ from apax.layers.readout import AtomisticReadout from apax.layers.scaling import PerElementScaleShift from apax.utils.math import fp64_sum -from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import space, partition DisplacementFn = Callable[[Array, Array], Array] -MDModel = Tuple[jax_md_reduced.partition.NeighborFn, Callable, Callable] +MDModel = Tuple[partition.NeighborFn, Callable, Callable] log = logging.getLogger(__name__) def canonicalize_neighbors(neighbor): - return neighbor.idx if isinstance(neighbor, jax_md_reduced.NeighborList) else neighbor + return neighbor.idx if isinstance(neighbor, partition.NeighborList) else neighbor def disp_fn(ri, rj, perturbation, box): - dR = jax_md_reduced.space.pairwise_displacement(ri, rj) - dR = jax_md_reduced.space.transform(box, dR) + dR = space.pairwise_displacement(ri, rj) + dR = space.transform(box, dR) if perturbation is not None: - dR = dR + jax_md_reduced.space.raw_transform(perturbation, dR) + dR = dR + space.raw_transform(perturbation, dR) # https://github.com/mir-group/nequip/blob/c56f48fcc9b4018a84e1ed28f762fadd5bc763f1/nequip/nn/_grad_output.py#L267 # https://github.com/sirmarcel/glp/blob/main/glp/calculators/utils.py # other codes do R = R + strain, not dR @@ -78,8 +78,8 @@ class EnergyModel(nn.Module): def setup(self): if np.all(self.init_box < 1e-6): # gas phase training and predicting - displacement_fn = jax_md_reduced.space.free()[0] - self.displacement = jax_md_reduced.space.map_bond(displacement_fn) + displacement_fn = space.free()[0] + self.displacement = space.map_bond(displacement_fn) elif self.inference_disp_fn is None: # for training on periodic systems self.displacement = vmap(disp_fn, (0, 0, None, None), 0) @@ -91,7 +91,7 @@ def __call__( self, R: Array, Z: Array, - neighbor: Union[jax_md_reduced.partition.NeighborList, Array], + neighbor: Union[partition.NeighborList, Array], box, offsets, perturbation=None, @@ -138,7 +138,7 @@ def __call__( self, R: Array, Z: Array, - neighbor: Union[jax_md_reduced.partition.NeighborList, Array], + neighbor: Union[partition.NeighborList, Array], box, offsets, ): diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..684203eb 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,10 +109,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/jax_md_reduced/__init__.py b/apax/utils/jax_md_reduced/__init__.py index 8a63f8bf..3bc9f80a 100644 --- a/apax/utils/jax_md_reduced/__init__.py +++ b/apax/utils/jax_md_reduced/__init__.py @@ -1,3 +1,11 @@ -from apax.utils.jax_md_reduced import partition, space, quantity +from apax.utils.jax_md_reduced import ( + partition, + space, + quantity, + simulate, + smap, + util, + dataclasses, +) -__all__ = ["partition", "space", "quantity"] +__all__ = ["partition", "space", "quantity", "simulate", "smap", "util", "dataclasses"] diff --git a/apax/utils/jax_md_reduced/dataclasses.py b/apax/utils/jax_md_reduced/dataclasses.py index f70790dc..df089ed9 100644 --- a/apax/utils/jax_md_reduced/dataclasses.py +++ b/apax/utils/jax_md_reduced/dataclasses.py @@ -24,50 +24,49 @@ def dataclass(clz): - """Create a class which can be passed to functional transformations. - - Jax transformations such as `jax.jit` and `jax.grad` require objects that are - immutable and can be mapped over using the `jax.tree_util` methods. - - The `dataclass` decorator makes it easy to define custom classes that can be - passed safely to Jax. - - Args: - clz: the class that will be transformed by the decorator. - Returns: - The new class. - """ - clz.set = lambda self, **kwargs: dataclasses.replace(self, **kwargs) - data_clz = dataclasses.dataclass(frozen=True)(clz) - meta_fields = [] - data_fields = [] - for name, field_info in data_clz.__dataclass_fields__.items(): - is_static = field_info.metadata.get('static', False) - if is_static: - meta_fields.append(name) - else: - data_fields.append(name) - - def iterate_clz(x): - meta = tuple(getattr(x, name) for name in meta_fields) - data = tuple(getattr(x, name) for name in data_fields) - return data, meta - - def clz_from_iterable(meta, data): - meta_args = tuple(zip(meta_fields, meta)) - data_args = tuple(zip(data_fields, data)) - kwargs = dict(meta_args + data_args) - return data_clz(**kwargs) - - jax.tree_util.register_pytree_node(data_clz, - iterate_clz, - clz_from_iterable) - - return data_clz + """Create a class which can be passed to functional transformations. + + Jax transformations such as `jax.jit` and `jax.grad` require objects that are + immutable and can be mapped over using the `jax.tree_util` methods. + + The `dataclass` decorator makes it easy to define custom classes that can be + passed safely to Jax. + + Args: + clz: the class that will be transformed by the decorator. + Returns: + The new class. + """ + clz.set = lambda self, **kwargs: dataclasses.replace(self, **kwargs) + data_clz = dataclasses.dataclass(frozen=True)(clz) + meta_fields = [] + data_fields = [] + for name, field_info in data_clz.__dataclass_fields__.items(): + is_static = field_info.metadata.get("static", False) + if is_static: + meta_fields.append(name) + else: + data_fields.append(name) + + def iterate_clz(x): + meta = tuple(getattr(x, name) for name in meta_fields) + data = tuple(getattr(x, name) for name in data_fields) + return data, meta + + def clz_from_iterable(meta, data): + meta_args = tuple(zip(meta_fields, meta)) + data_args = tuple(zip(data_fields, data)) + kwargs = dict(meta_args + data_args) + return data_clz(**kwargs) + + jax.tree_util.register_pytree_node(data_clz, iterate_clz, clz_from_iterable) + + return data_clz def static_field(): - return dataclasses.field(metadata={'static': True}) + return dataclasses.field(metadata={"static": True}) + replace = dataclasses.replace asdict = dataclasses.asdict @@ -75,5 +74,7 @@ def static_field(): is_dataclass = dataclasses.is_dataclass fields = dataclasses.fields field = dataclasses.field + + def unpack(dc) -> tuple: return tuple(getattr(dc, field.name) for field in dataclasses.fields(dc)) diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 3f9a79d4..b1f48603 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -20,7 +20,7 @@ import numpy as onp from jax.core import ShapedArray from jax import jit, vmap, eval_shape, lax -from enum import IntEnum ,Enum +from enum import IntEnum, Enum from apax.utils.jax_md_reduced import util, space, dataclasses Array = util.Array @@ -38,324 +38,394 @@ def _cell_size(box, minimum_cell_size) -> Array: - cells_per_side = jnp.floor(box / minimum_cell_size) - return box / cells_per_side + cells_per_side = jnp.floor(box / minimum_cell_size) + return box / cells_per_side def _fractional_cell_size(box, cutoff): - if jnp.isscalar(box) or box.ndim == 0: - return cutoff / box - elif box.ndim == 1: - return cutoff / jnp.min(box) - elif box.ndim == 2: - if box.shape[0] == 1: - return 1 / jnp.floor(box[0, 0] / cutoff) - elif box.shape[0] == 2: - xx = box[0, 0] - yy = box[1, 1] - xy = box[0, 1] / yy - - nx = xx / jnp.sqrt(1 + xy**2) - ny = yy - - nmin = jnp.floor(jnp.min(jnp.array([nx, ny])) / cutoff) - nmin = jnp.where(nmin == 0, 1, nmin) - return 1 / nmin - elif box.shape[0] == 3: - xx = box[0, 0] - yy = box[1, 1] - zz = box[2, 2] - xy = box[0, 1] / yy - xz = box[0, 2] / zz - yz = box[1, 2] / zz - - nx = xx / jnp.sqrt(1 + xy**2 + (xy * yz - xz)**2) - ny = yy / jnp.sqrt(1 + yz**2) - nz = zz - - nmin = jnp.floor(jnp.min(jnp.array([nx, ny, nz])) / cutoff) - nmin = jnp.where(nmin == 0, 1, nmin) - return 1 / nmin + if jnp.isscalar(box) or box.ndim == 0: + return cutoff / box + elif box.ndim == 1: + return cutoff / jnp.min(box) + elif box.ndim == 2: + if box.shape[0] == 1: + return 1 / jnp.floor(box[0, 0] / cutoff) + elif box.shape[0] == 2: + xx = box[0, 0] + yy = box[1, 1] + xy = box[0, 1] / yy + + nx = xx / jnp.sqrt(1 + xy**2) + ny = yy + + nmin = jnp.floor(jnp.min(jnp.array([nx, ny])) / cutoff) + nmin = jnp.where(nmin == 0, 1, nmin) + return 1 / nmin + elif box.shape[0] == 3: + xx = box[0, 0] + yy = box[1, 1] + zz = box[2, 2] + xy = box[0, 1] / yy + xz = box[0, 2] / zz + yz = box[1, 2] / zz + + nx = xx / jnp.sqrt(1 + xy**2 + (xy * yz - xz) ** 2) + ny = yy / jnp.sqrt(1 + yz**2) + nz = zz + + nmin = jnp.floor(jnp.min(jnp.array([nx, ny, nz])) / cutoff) + nmin = jnp.where(nmin == 0, 1, nmin) + return 1 / nmin + else: + raise ValueError( + f"Expected box to be either 1-, 2-, or 3-dimensional found {box.shape[0]}" + ) else: - raise ValueError('Expected box to be either 1-, 2-, or 3-dimensional ' - f'found {box.shape[0]}') - else: - raise ValueError('Expected box to be either a scalar, a vector, or a ' - f'matrix. Found {type(box)}.') + raise ValueError( + "Expected box to be either a scalar, a vector, or a " + f"matrix. Found {type(box)}." + ) + def _displacement_or_metric_to_metric_sq( - displacement_or_metric: DisplacementOrMetricFn) -> MetricFn: - """Checks whether or not a displacement or metric was provided.""" - for dim in range(1, 4): - try: - R = ShapedArray((dim,), f32) - dR_or_dr = eval_shape(displacement_or_metric, R, R, t=0) - if len(dR_or_dr.shape) == 0: - return lambda Ra, Rb, **kwargs: \ - displacement_or_metric(Ra, Rb, **kwargs) ** 2 - else: - return lambda Ra, Rb, **kwargs: space.square_distance( - displacement_or_metric(Ra, Rb, **kwargs)) - except TypeError: - continue - except ValueError: - continue - raise ValueError( - 'Canonicalize displacement not implemented for spatial dimension larger' - 'than 4.') + displacement_or_metric: DisplacementOrMetricFn, +) -> MetricFn: + """Checks whether or not a displacement or metric was provided.""" + for dim in range(1, 4): + try: + R = ShapedArray((dim,), f32) + dR_or_dr = eval_shape(displacement_or_metric, R, R, t=0) + if len(dR_or_dr.shape) == 0: + return ( + lambda Ra, Rb, **kwargs: displacement_or_metric(Ra, Rb, **kwargs) ** 2 + ) + else: + return lambda Ra, Rb, **kwargs: space.square_distance( + displacement_or_metric(Ra, Rb, **kwargs) + ) + except TypeError: + continue + except ValueError: + continue + raise ValueError( + "Canonicalize displacement not implemented for spatial dimension largerthan 4." + ) + # Neighbor Lists @dataclasses.dataclass class CellList: - """Stores the spatial partition of a system into a cell list. - - See :meth:`cell_list` for details on the construction / specification. - Cell list buffers all have a common shape, S, where - * `S = [cell_count_x, cell_count_y, cell_capacity]` - * `S = [cell_count_x, cell_count_y, cell_count_z, cell_capacity]` - in two- and three-dimensions respectively. It is assumed that each cell has - the same capacity. - - Attributes: - position_buffer: An ndarray of floating point positions with shape - `S + [spatial_dimension]`. - id_buffer: An ndarray of int32 particle ids of shape `S`. Note that empty - slots are specified by `id = N` where `N` is the number of particles in - the system. - named_buffer: A dictionary of ndarrays of shape `S + [...]`. This contains - side data placed into the cell list. - did_buffer_overflow: A boolean specifying whether or not the cell list - exceeded the maximum allocated capacity. - cell_capacity: An integer specifying the maximum capacity of each cell in - the cell list. - update_fn: A function that updates the cell list at a fixed capacity. - """ - position_buffer: Array - id_buffer: Array - named_buffer: Dict[str, Array] - - did_buffer_overflow: Array - - cell_capacity: int = dataclasses.static_field() - cell_size: float = dataclasses.static_field() - - update_fn: Callable[..., 'CellList'] = \ - dataclasses.static_field() - - def update(self, position: Array, **kwargs) -> 'CellList': - cl_data = (self.cell_capacity, self.did_buffer_overflow, self.update_fn) - return self.update_fn(position, cl_data, **kwargs) - - @property - def kwarg_buffers(self): - logging.warning('kwarg_buffers renamed to named_buffer. The name ' - 'kwarg_buffers will be depricated.') - return self.named_buffer + """Stores the spatial partition of a system into a cell list. + + See :meth:`cell_list` for details on the construction / specification. + Cell list buffers all have a common shape, S, where + * `S = [cell_count_x, cell_count_y, cell_capacity]` + * `S = [cell_count_x, cell_count_y, cell_count_z, cell_capacity]` + in two- and three-dimensions respectively. It is assumed that each cell has + the same capacity. + + Attributes: + position_buffer: An ndarray of floating point positions with shape + `S + [spatial_dimension]`. + id_buffer: An ndarray of int32 particle ids of shape `S`. Note that empty + slots are specified by `id = N` where `N` is the number of particles in + the system. + named_buffer: A dictionary of ndarrays of shape `S + [...]`. This contains + side data placed into the cell list. + did_buffer_overflow: A boolean specifying whether or not the cell list + exceeded the maximum allocated capacity. + cell_capacity: An integer specifying the maximum capacity of each cell in + the cell list. + update_fn: A function that updates the cell list at a fixed capacity. + """ + + position_buffer: Array + id_buffer: Array + named_buffer: Dict[str, Array] + + did_buffer_overflow: Array + + cell_capacity: int = dataclasses.static_field() + cell_size: float = dataclasses.static_field() + + update_fn: Callable[..., "CellList"] = dataclasses.static_field() + + def update(self, position: Array, **kwargs) -> "CellList": + cl_data = (self.cell_capacity, self.did_buffer_overflow, self.update_fn) + return self.update_fn(position, cl_data, **kwargs) + + @property + def kwarg_buffers(self): + logging.warning( + "kwarg_buffers renamed to named_buffer. The name " + "kwarg_buffers will be depricated." + ) + return self.named_buffer -class NeighborListFormat(Enum): - """An enum listing the different neighbor list formats. - - Attributes: - Dense: A dense neighbor list where the ids are a square matrix - of shape `(N, max_neighbors_per_atom)`. Here the capacity of the neighbor - list must scale with the highest connectivity neighbor. - Sparse: A sparse neighbor list where the ids are a rectangular - matrix of shape `(2, max_neighbors)` specifying the start / end particle - of each neighbor pair. - OrderedSparse: A sparse neighbor list whose format is the same as `Sparse` - where only bonds with i < j are included. - """ - Dense = 0 - Sparse = 1 - OrderedSparse = 2 class PartitionErrorCode(IntEnum): - """An enum specifying different error codes. - - Attributes: - NONE: Means that no error was encountered during simulation. - NEIGHBOR_LIST_OVERFLOW: Indicates that the neighbor list was not large - enough to contain all of the particles. This should indicate that it is - necessary to allocate a new neighbor list. - CELL_LIST_OVERFLOW: Indicates that the cell list was not large enough to - contain all of the particles. This should indicate that it is necessary - to allocate a new cell list. - CELL_SIZE_TOO_SMALL: Indicates that the size of cells in a cell list was - not large enough to properly capture particle interactions. This - indicates that it is necessary to allcoate a new cell list with larger - cells. - MALFORMED_BOX: Indicates that a box matrix was not properly upper - triangular. - """ - NONE = 0 - NEIGHBOR_LIST_OVERFLOW = 1 << 0 - CELL_LIST_OVERFLOW = 1 << 1 - CELL_SIZE_TOO_SMALL = 1 << 2 - MALFORMED_BOX = 1 << 3 + """An enum specifying different error codes. + + Attributes: + NONE: Means that no error was encountered during simulation. + NEIGHBOR_LIST_OVERFLOW: Indicates that the neighbor list was not large + enough to contain all of the particles. This should indicate that it is + necessary to allocate a new neighbor list. + CELL_LIST_OVERFLOW: Indicates that the cell list was not large enough to + contain all of the particles. This should indicate that it is necessary + to allocate a new cell list. + CELL_SIZE_TOO_SMALL: Indicates that the size of cells in a cell list was + not large enough to properly capture particle interactions. This + indicates that it is necessary to allcoate a new cell list with larger + cells. + MALFORMED_BOX: Indicates that a box matrix was not properly upper + triangular. + """ + + NONE = 0 + NEIGHBOR_LIST_OVERFLOW = 1 << 0 + CELL_LIST_OVERFLOW = 1 << 1 + CELL_SIZE_TOO_SMALL = 1 << 2 + MALFORMED_BOX = 1 << 3 + + PEC = PartitionErrorCode @dataclasses.dataclass class PartitionError: - """A struct containing error codes while building / updating neighbor lists. + """A struct containing error codes while building / updating neighbor lists. + + Attributes: + code: An array storing the error code. See `PartitionErrorCode` for + details. + """ + + code: Array + + def update(self, bit: bytes, pred: Array) -> Array: + """Possibly adds an error based on a predicate.""" + zero = jnp.zeros((), jnp.uint8) + bit = jnp.array(bit, dtype=jnp.uint8) + return PartitionError(self.code | jnp.where(pred, bit, zero)) + + +class NeighborListFormat(Enum): + """An enum listing the different neighbor list formats. + + Attributes: + Dense: A dense neighbor list where the ids are a square matrix + of shape `(N, max_neighbors_per_atom)`. Here the capacity of the neighbor + list must scale with the highest connectivity neighbor. + Sparse: A sparse neighbor list where the ids are a rectangular + matrix of shape `(2, max_neighbors)` specifying the start / end particle + of each neighbor pair. + OrderedSparse: A sparse neighbor list whose format is the same as `Sparse` + where only bonds with i < j are included. + """ + + Dense = 0 + Sparse = 1 + OrderedSparse = 2 + - Attributes: - code: An array storing the error code. See `PartitionErrorCode` for - details. - """ - code: Array +@dataclasses.dataclass +class NeighborList: + """A struct containing the state of a Neighbor List. + + Attributes: + idx: For an N particle system this is an `[N, max_occupancy]` array of + integers such that `idx[i, j]` is the j-th neighbor of particle i. + reference_position: The positions of particles when the neighbor list was + constructed. This is used to decide whether the neighbor list ought to be + updated. + error: An error code that is used to identify errors that occured during + neighbor list construction. See `PartitionError` and `PartitionErrorCode` + for details. + cell_list_capacity: An optional integer specifying the capacity of the cell + list used as an intermediate step in the creation of the neighbor list. + max_occupancy: A static integer specifying the maximum size of the + neighbor list. Changing this will invoke a recompilation. + format: A NeighborListFormat enum specifying the format of the neighbor + list. + cell_size: A float specifying the current minimum size of the cells used + in cell list construction. + cell_list_fn: The function used to construct the cell list. + update_fn: A static python function used to update the neighbor list. + """ + + idx: Array + reference_position: Array + error: PartitionError + cell_list_capacity: Optional[int] = dataclasses.static_field() + max_occupancy: int = dataclasses.static_field() + + format: NeighborListFormat = dataclasses.static_field() + cell_size: Optional[float] = dataclasses.static_field() + cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() + update_fn: Callable[ + [Array, "NeighborList"], "NeighborList" + ] = dataclasses.static_field() + + def update(self, position: Array, **kwargs) -> "NeighborList": + return self.update_fn(position, self, **kwargs) + + @property + def did_buffer_overflow(self) -> bool: + return self.error.code & (PEC.NEIGHBOR_LIST_OVERFLOW | PEC.CELL_LIST_OVERFLOW) + + @property + def cell_size_too_small(self) -> bool: + return self.error.code & PEC.CELL_SIZE_TOO_SMALL - def update(self, bit: bytes, pred: Array) -> Array: - """Possibly adds an error based on a predicate.""" - zero = jnp.zeros((), jnp.uint8) - bit = jnp.array(bit, dtype=jnp.uint8) - return PartitionError(self.code | jnp.where(pred, bit, zero)) + @property + def malformed_box(self) -> bool: + return self.error.code & PEC.MALFORMED_BOX - def __str__(self) -> str: - """Produces a string representation of the error code.""" - if not jnp.any(self.code): - return '' + def __str__(self) -> str: + """Produces a string representation of the error code.""" + if not jnp.any(self.code): + return "" - if jnp.any(self.code & PEC.NEIGHBOR_LIST_OVERFLOW): - return 'Partition Error: Neighbor list buffer overflow.' + if jnp.any(self.code & PEC.NEIGHBOR_LIST_OVERFLOW): + return "Partition Error: Neighbor list buffer overflow." - if jnp.any(self.code & PEC.CELL_LIST_OVERFLOW): - return 'Partition Error: Cell list buffer overflow' + if jnp.any(self.code & PEC.CELL_LIST_OVERFLOW): + return "Partition Error: Cell list buffer overflow" - if jnp.any(self.code & PEC.CELL_SIZE_TOO_SMALL): - return 'Partition Error: Cell size too small' + if jnp.any(self.code & PEC.CELL_SIZE_TOO_SMALL): + return "Partition Error: Cell size too small" - if jnp.any(self.code & PEC.MALFORMED_BOX): - return ('Partition Error: Incorrect box format. Expecting upper ' - 'triangular.') + if jnp.any(self.code & PEC.MALFORMED_BOX): + return "Partition Error: Incorrect box format. Expecting upper triangular." - raise ValueError(f'Unexpected Error Code {self.code}.') + raise ValueError(f"Unexpected Error Code {self.code}.") + + __repr__ = __str__ - __repr__ = __str__ @dataclasses.dataclass class NeighborList: - """A struct containing the state of a Neighbor List. - - Attributes: - idx: For an N particle system this is an `[N, max_occupancy]` array of - integers such that `idx[i, j]` is the j-th neighbor of particle i. - reference_position: The positions of particles when the neighbor list was - constructed. This is used to decide whether the neighbor list ought to be - updated. - error: An error code that is used to identify errors that occured during - neighbor list construction. See `PartitionError` and `PartitionErrorCode` - for details. - cell_list_capacity: An optional integer specifying the capacity of the cell - list used as an intermediate step in the creation of the neighbor list. - max_occupancy: A static integer specifying the maximum size of the - neighbor list. Changing this will invoke a recompilation. - format: A NeighborListFormat enum specifying the format of the neighbor - list. - cell_size: A float specifying the current minimum size of the cells used - in cell list construction. - cell_list_fn: The function used to construct the cell list. - update_fn: A static python function used to update the neighbor list. - """ - idx: Array - reference_position: Array - error: PartitionError - cell_list_capacity: Optional[int] = dataclasses.static_field() - max_occupancy: int = dataclasses.static_field() - - format: NeighborListFormat = dataclasses.static_field() - cell_size: Optional[float] = dataclasses.static_field() - cell_list_fn: Callable[[Array, CellList], - CellList] = dataclasses.static_field() - update_fn: Callable[[Array, 'NeighborList'], - 'NeighborList'] = dataclasses.static_field() - - def update(self, position: Array, **kwargs) -> 'NeighborList': - return self.update_fn(position, self, **kwargs) - - @property - def did_buffer_overflow(self) -> bool: - return self.error.code & (PEC.NEIGHBOR_LIST_OVERFLOW | - PEC.CELL_LIST_OVERFLOW) - - @property - def cell_size_too_small(self) -> bool: - return self.error.code & PEC.CELL_SIZE_TOO_SMALL - - @property - def malformed_box(self) -> bool: - return self.error.code & PEC.MALFORMED_BOX + """A struct containing the state of a Neighbor List. + + Attributes: + idx: For an N particle system this is an `[N, max_occupancy]` array of + integers such that `idx[i, j]` is the j-th neighbor of particle i. + reference_position: The positions of particles when the neighbor list was + constructed. This is used to decide whether the neighbor list ought to be + updated. + error: An error code that is used to identify errors that occured during + neighbor list construction. See `PartitionError` and `PartitionErrorCode` + for details. + cell_list_capacity: An optional integer specifying the capacity of the cell + list used as an intermediate step in the creation of the neighbor list. + max_occupancy: A static integer specifying the maximum size of the + neighbor list. Changing this will invoke a recompilation. + format: A NeighborListFormat enum specifying the format of the neighbor + list. + cell_size: A float specifying the current minimum size of the cells used + in cell list construction. + cell_list_fn: The function used to construct the cell list. + update_fn: A static python function used to update the neighbor list. + """ + + idx: Array + reference_position: Array + error: PartitionError + cell_list_capacity: Optional[int] = dataclasses.static_field() + max_occupancy: int = dataclasses.static_field() + + format: NeighborListFormat = dataclasses.static_field() + cell_size: Optional[float] = dataclasses.static_field() + cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() + update_fn: Callable[ + [Array, "NeighborList"], "NeighborList" + ] = dataclasses.static_field() + + def update(self, position: Array, **kwargs) -> "NeighborList": + return self.update_fn(position, self, **kwargs) + + @property + def did_buffer_overflow(self) -> bool: + return self.error.code & (PEC.NEIGHBOR_LIST_OVERFLOW | PEC.CELL_LIST_OVERFLOW) + + @property + def cell_size_too_small(self) -> bool: + return self.error.code & PEC.CELL_SIZE_TOO_SMALL + + @property + def malformed_box(self) -> bool: + return self.error.code & PEC.MALFORMED_BOX + def is_sparse(fmt: NeighborListFormat) -> bool: - return (fmt is NeighborListFormat.Sparse or - fmt is NeighborListFormat.OrderedSparse) + return fmt is NeighborListFormat.Sparse or fmt is NeighborListFormat.OrderedSparse def is_format_valid(fmt: NeighborListFormat): - if fmt not in list(NeighborListFormat): - raise ValueError(( - 'Neighbor list format must be a member of NeighborListFormat' - f' found {fmt}.')) + if fmt not in list(NeighborListFormat): + raise ValueError( + f"Neighbor list format must be a member of NeighborListFormat found {fmt}." + ) def is_box_valid(box: Array) -> bool: - if jnp.isscalar(box) or box.ndim == 0 or box.ndim == 1: - return True - if box.ndim == 2: - return jnp.triu(box) == box - return False + if jnp.isscalar(box) or box.ndim == 0 or box.ndim == 1: + return True + if box.ndim == 2: + return jnp.triu(box) == box + return False @dataclasses.dataclass class NeighborListFns: - """A struct containing functions to allocate and update neighbor lists. - - Attributes: - allocate: A function to allocate a new neighbor list. This function cannot - be compiled, since it uses the values of positions to infer the shapes. - update: A function to update a neighbor list given a new set of positions - and a previously allocated neighbor list. - """ - allocate: Callable[..., NeighborList] = dataclasses.static_field() - update: Callable[[Array, NeighborList], - NeighborList] = dataclasses.static_field() - - def __call__(self, - position: Array, - neighbors: Optional[NeighborList] = None, - extra_capacity: int = 0, - **kwargs) -> NeighborList: - """A function for backward compatibility with previous neighbor lists. + """A struct containing functions to allocate and update neighbor lists. - Args: - position: An `(N, dim)` array of particle positions. - neighbors: An optional neighbor list object. If it is provided then - the function updates the neighbor list, otherwise it allocates a new - neighbor list. - extra_capacity: Extra capacity to add if allocating the neighbor list. - Returns: - A neighbor list object. + Attributes: + allocate: A function to allocate a new neighbor list. This function cannot + be compiled, since it uses the values of positions to infer the shapes. + update: A function to update a neighbor list given a new set of positions + and a previously allocated neighbor list. """ - logging.warning('Using a deprecated code path to create / update neighbor ' - 'lists. It will be removed in a later version of JAX MD. ' - 'Using `neighbor_fn.allocate` and `neighbor_fn.update` ' - 'is preferred.') - if neighbors is None: - return self.allocate(position, extra_capacity, **kwargs) - return self.update(position, neighbors, **kwargs) - - def __iter__(self): - return iter((self.allocate, self.update)) -NeighborFn = Callable[[Array, Optional[NeighborList], Optional[int]], - NeighborList] + allocate: Callable[..., NeighborList] = dataclasses.static_field() + update: Callable[[Array, NeighborList], NeighborList] = dataclasses.static_field() -Sparse = NeighborListFormat.Sparse + def __call__( + self, + position: Array, + neighbors: Optional[NeighborList] = None, + extra_capacity: int = 0, + **kwargs, + ) -> NeighborList: + """A function for backward compatibility with previous neighbor lists. + + Args: + position: An `(N, dim)` array of particle positions. + neighbors: An optional neighbor list object. If it is provided then + the function updates the neighbor list, otherwise it allocates a new + neighbor list. + extra_capacity: Extra capacity to add if allocating the neighbor list. + Returns: + A neighbor list object. + """ + logging.warning( + "Using a deprecated code path to create / update neighbor " + "lists. It will be removed in a later version of JAX MD. " + "Using `neighbor_fn.allocate` and `neighbor_fn.update` " + "is preferred." + ) + if neighbors is None: + return self.allocate(position, extra_capacity, **kwargs) + return self.update(position, neighbors, **kwargs) + def __iter__(self): + return iter((self.allocate, self.update)) +NeighborFn = Callable[[Array, Optional[NeighborList], Optional[int]], NeighborList] # def cell_list(box_size: Box, @@ -405,8 +475,6 @@ def __iter__(self): # return None #CellListFns(allocate_fn, update_fn) # pytype: disable=wrong-arg-count - - def neighbor_list( displacement_or_metric: DisplacementOrMetricFn, box: Box, @@ -418,7 +486,7 @@ def neighbor_list( custom_mask_function: Optional[MaskFn] = None, fractional_coordinates: bool = False, format: NeighborListFormat = NeighborListFormat.Dense, - **static_kwargs + **static_kwargs, ) -> NeighborFn: """Returns a function that builds a list neighbors for collections of points. @@ -626,7 +694,9 @@ def neighbor_fn(position_and_error, max_occupancy=None): cl_capacity = None idx = candidate_fn(position) else: - raise NotImplementedError("Cell lists not implemented in apax' reduced jaxmd") + raise NotImplementedError( + "Cell lists not implemented in apax' reduced jaxmd" + ) # err = err.update(PEC.CELL_LIST_OVERFLOW, cl.did_buffer_overflow) # idx = cell_list_candidate_fn(cl, position) # cl_capacity = cl.cell_capacity @@ -665,7 +735,7 @@ def neighbor_fn(position_and_error, max_occupancy=None): cl_capacity, max_occupancy, format, - 0, # cell_size + 0, # cell_size cl_fn, update_fn, ) # pytype: disable=wrong-arg-count @@ -715,3 +785,8 @@ def update_fn(position: Array, neighbors, **kwargs): return neighbor_list_fn(position, neighbors, **kwargs) return NeighborListFns(allocate_fn, update_fn) # pytype: disable=wrong-arg-count + + +Dense = NeighborListFormat.Dense +Sparse = NeighborListFormat.Sparse +OrderedSparse = NeighborListFormat.OrderedSparse diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py index af78543e..58f200b5 100644 --- a/apax/utils/jax_md_reduced/quantity.py +++ b/apax/utils/jax_md_reduced/quantity.py @@ -10,4 +10,737 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. \ No newline at end of file +# limitations under the License. + +"""Describes different physical quantities.""" + + +from typing import TypeVar, Callable, Union, Tuple, Optional, Any + +from absl import logging + +from jax import grad, vmap, eval_shape +from jax.tree_util import tree_map, tree_reduce +import jax.numpy as jnp +from jax import ops +from jax import ShapeDtypeStruct +from jax.tree_util import tree_map, tree_reduce +from jax.scipy.special import gammaln + +from apax.utils.jax_md_reduced import space, dataclasses, partition, util + +import functools +import operator + +partial = functools.partial + +# Types + + +Array = util.Array +f32 = util.f32 +f64 = util.f64 + +DisplacementFn = space.DisplacementFn +MetricFn = space.MetricFn +Box = space.Box + +EnergyFn = Callable[..., Array] +ForceFn = Callable[..., Array] + +T = TypeVar("T") +InitFn = Callable[..., T] +ApplyFn = Callable[[T], T] +Simulator = Tuple[InitFn, ApplyFn] + + +# Functions + + +def force(energy_fn: EnergyFn) -> ForceFn: + """Computes the force as the negative gradient of an energy.""" + return grad(lambda R, *args, **kwargs: -energy_fn(R, *args, **kwargs)) + + +def clipped_force(energy_fn: EnergyFn, max_force: float) -> ForceFn: + force_fn = force(energy_fn) + + def wrapped_force_fn(R, *args, **kwargs): + force = force_fn(R, *args, **kwargs) + force_norm = jnp.linalg.norm(force, axis=-1, keepdims=True) + return jnp.where(force_norm > max_force, force / force_norm * max_force, force) + + return wrapped_force_fn + + +def canonicalize_force(energy_or_force_fn: Union[EnergyFn, ForceFn]) -> ForceFn: + _force_fn = None + + def force_fn(R, **kwargs): + nonlocal _force_fn + if _force_fn is None: + out_shaped = eval_shape(energy_or_force_fn, R, **kwargs) + if isinstance(out_shaped, ShapeDtypeStruct) and out_shaped.shape == (): + _force_fn = force(energy_or_force_fn) + else: + # Check that the output has the right shape to be a force. + is_valid_force = tree_reduce( + lambda x, y: x and y, + tree_map(lambda x, y: x.shape == y.shape, out_shaped, R), + True, + ) + if not is_valid_force: + raise ValueError( + "Provided function should be compatible with " + "either an energy or a force. Found a function " + f"whose output has shape {out_shaped}." + ) + + _force_fn = energy_or_force_fn + return _force_fn(R, **kwargs) + + return force_fn + + +@functools.singledispatch +def count_dof(position: Array) -> int: + util.check_custom_simulation_type(position) + return tree_reduce(lambda accum, x: accum + x.size, position, 0) + + +def volume(dimension: int, box: Box) -> float: + if jnp.isscalar(box) or not box.ndim: + return box**dimension + elif box.ndim == 1: + return jnp.prod(box) + elif box.ndim == 2: + return jnp.linalg.det(box) + raise ValueError(f"Box must be either: a scalar, a vector, or a matrix. Found {box}.") + + +def kinetic_energy( + *unused_args, + momentum: Array = None, + velocity: Array = None, + mass: Array = 1.0, +) -> float: + """Computes the kinetic energy of a system. + + To avoid ambiguity, either momentum or velocity must be passed explicitly + as a keyword argument. + + Args: + momentum: Array specifying the momentum of the system. + velocity: Array specifying the velocity of the system. + mass: Array specifying the mass of the constituents. + + Returns: + The kinetic energy of the system. + """ + if unused_args: + raise ValueError( + "To use the kinetic energy function, you must explicitly " + "pass either momentum or velocity as a keyword argument." + ) + if momentum is not None and velocity is not None: + raise ValueError( + "To use the kinetic energy function, you must pass either" + " a momentum or a velocity." + ) + + k = (lambda v, m: v**2 * m) if momentum is None else (lambda p, m: p**2 / m) + q = velocity if momentum is None else momentum + util.check_custom_simulation_type(q) + + ke = tree_map(lambda m, q: 0.5 * util.high_precision_sum(k(q, m)), mass, q) + return tree_reduce(operator.add, ke, 0.0) + + +def temperature( + *unused_args, + momentum: Array = None, + velocity: Array = None, + mass: Array = 1.0, +) -> float: + """Computes the temperature of a system. + + To avoid ambiguity, either momentum or velocity must be passed explicitly + as a keyword argument. + + Args: + momentum: Array specifying the momentum of the system. + velocity: Array specifying the velocity of the system. + mass: Array specifying the mass of the constituents. + + Returns: + The temperature of the system in units of the Boltzmann constant. + """ + if unused_args: + raise ValueError( + "To use the kinetic energy function, you must explicitly " + "pass either momentum or velocity as a keyword argument." + ) + if momentum is not None and velocity is not None: + raise ValueError( + "To use the kinetic energy function, you must pass either" + " a momentum or a velocity." + ) + + t = (lambda v, m: v**2 * m) if momentum is None else (lambda p, m: p**2 / m) + q = velocity if momentum is None else momentum + util.check_custom_simulation_type(q) + + dof = count_dof(q) + + kT = tree_map(lambda m, q: util.high_precision_sum(t(q, m)) / dof, mass, q) + return tree_reduce(operator.add, kT, 0.0) + + +def pressure( + energy_fn: EnergyFn, position: Array, box: Box, kinetic_energy: float = 0.0, **kwargs +) -> float: + """Computes the internal pressure of a system. + + Args: + energy_fn: A function that computes the energy of the system. This + function must take as an argument `perturbation` which perturbs the + box shape. Any energy function constructed using `smap` or in `energy.py` + with a standard space will satisfy this property. + position: An array of particle positions. + box: A box specifying the shape of the simulation volume. Used to infer the + volume of the unit cell. + kinetic_energy: A float specifying the kinetic energy of the system. + + Returns: + A float specifying the pressure of the system. + """ + dim = position.shape[1] + + def U(eps): + try: + return energy_fn(position, box=box, perturbation=(1 + eps), **kwargs) + except space.UnexpectedBoxException: + return energy_fn(position, perturbation=(1 + eps), **kwargs) + + dUdV = grad(U) + vol_0 = volume(dim, box) + + return 1 / (dim * vol_0) * (2 * kinetic_energy - dUdV(0.0)) + + +def stress( + energy_fn: EnergyFn, + position: Array, + box: Box, + mass: Array = 1.0, + velocity: Optional[Array] = None, + **kwargs, +) -> Array: + """Computes the internal stress of a system. + + Args: + energy_fn: A function that computes the energy of the system. This + function must take as an argument `perturbation` which perturbs the + box shape. Any energy function constructed using `smap` or in `energy.py` + with a standard space will satisfy this property. + position: An array of particle positions. + box: A box specifying the shape of the simulation volume. Used to infer the + volume of the unit cell. + mass: The mass of the particles; only used to compute the kinetic + contribution if `velocity` is not `None`. + velocity: An array of atomic velocities. + + Returns: + A float specifying the pressure of the system. + """ + dim = position.shape[1] + + zero = jnp.zeros((dim, dim), position.dtype) + I = jnp.eye(dim, dtype=position.dtype) + + def U(eps): + try: + return energy_fn(position, box=box, perturbation=(I + eps), **kwargs) + except space.UnexpectedBoxException: + return energy_fn(position, perturbation=(I + eps), **kwargs) + + dUdV = grad(U) + vol_0 = volume(dim, box) + + VxV = 0.0 + if velocity is not None: + V = velocity + VxV = util.high_precision_sum(mass * V[:, None, :] * V[:, :, None], axis=0) + + return 1 / vol_0 * (VxV - dUdV(zero)) + + +def cosine_angle_between_two_vectors(dR_12: Array, dR_13: Array) -> Array: + dr_12 = space.distance(dR_12) + 1e-7 + dr_13 = space.distance(dR_13) + 1e-7 + cos_angle = jnp.dot(dR_12, dR_13) / dr_12 / dr_13 + return jnp.clip(cos_angle, -1.0, 1.0) + + +def cosine_angles(dR: Array) -> Array: + """Returns cosine of angles for all atom triplets. + + Args: + dR: Matrix of displacements; `ndarray(shape=[num_atoms, num_neighbors, + spatial_dim])`. + + Returns: + Tensor of cosine of angles; + `ndarray(shape=[num_atoms, num_neighbors, num_neighbors])`. + """ + + angles_between_all_triplets = vmap( + vmap(vmap(cosine_angle_between_two_vectors, (0, None)), (None, 0)), 0 + ) + return angles_between_all_triplets(dR, dR) + + +def is_integer(x: Array) -> bool: + return x.dtype == jnp.int32 or x.dtype == jnp.int64 + + +def average_pair_correlation_results(gofr, species=None): + """Calculate species-based averages of pair correlations. + + Average the results of pair_correlation or pair_correlation_neighbor_list, + appropriately taking species information into account. + + When species=None, gofr is expected to be an array of shape (N,nr), where N is + the number of species and nr is the number of radii to be considered. The + average is calculated over all particles, so an array of shape (nr,) is + returned. + + When species is specified, gofr is expected to be a list of nspecies arrays, + each of shape (N,nr), where nspecies is the number of unique species types. + Here, the average is carried out separately for every pair of species, so the + returned array has shape (nspecies, nspecies, nr). + + Args: + gofr: array of shape (N,nr) or a list of arrays of shape (N,nr), where nr is + the number of radii for which :math:`g(r)` is calculated. + species: Optional. Array of shape (N,) specifying the species of each + particle. + + Returns: + An array of shape (nr,) for species=None, otherwise an array of shape + (nspecies, nspecies, nr), where nspecies is the number of unique species. + """ + if species is None: + return jnp.mean(gofr, axis=0) + species_types = jnp.unique(species) # note: this returns in sorted order + return jnp.array( + [ + [jnp.mean(gofr[si][species == s], axis=0) for s in species_types] + for si in range(species_types.size) + ] + ) + + +def pair_correlation( + displacement_or_metric: Union[DisplacementFn, MetricFn], + radii: Array, + sigma: float, + species: Array = None, + eps: float = 1e-7, + compute_average: bool = False, +): + """Computes the pair correlation function at a mesh of distances. + + The pair correlation function measures the number of particles at a given + distance from a central particle. The pair correlation function is defined by + + .. math:: + g(r) = <\sum_{i \\neq j}\delta(r - |r_i - r_j|)> + + We make the approximation, + + .. math:: + \delta(r) \\approx {1 \over \sqrt{2\pi\sigma^2}e^{-r / (2\sigma^2)}} + + Args: + displacement_or_metric: + A function that computes the displacement or distance between two points. + radii: An array of radii at which we would like to compute :math:`g(r)`. + sigima: A float specifying the width of the approximating Gaussian. + species: An optional array specifying the species of each particle. If + species is None then we compute a single :math:`g(r)` for all particles, + otherwise we compute one :math:`g(r)` for each species. + eps: A small additive constant used to ensure stability if the radius is + zero. + + Returns: + A function `g_fn` that computes the pair correlation function for a + collection of particles. + + :math:`g(r)` is calculated separately for each particle. For species=None, the + output of `g_fn` is an array of shape (N, nr), where N is the number of + particles passed to `g_fn` and nr is the size of radii (the number of points + at which we calculate :math:`g(r)`. When species is specified, the output is a + list of nspecies arrays, each of shape (N, nr), where nspecies is the number + of unique species. If `gofr` is the output of `g_fn`, then gofr[si][i] gives + the :math:`g(r)` for particle i considering only pair particles of species si. + + Note: when species is specified, the returned list is in the order of the + sorted unique species indices, not the order in which they appear. + + """ + d = space.canonicalize_displacement_or_metric(displacement_or_metric) + d = space.map_product(d) + + inv_rad = 1 / (radii + eps) + + def pairwise(dr, dim): + return jnp.exp(-f32(0.5) * (dr - radii) ** 2 / sigma**2) * inv_rad ** (dim - 1) + + pairwise = vmap(vmap(pairwise, (0, None)), (0, None)) + + if species is None: + + def g_fn(R): + dim = R.shape[-1] + mask = 1 - jnp.eye(R.shape[0], dtype=R.dtype) + g_R = jnp.sum(mask[:, :, jnp.newaxis] * pairwise(d(R, R), dim), axis=(1,)) + if compute_average: + g_R = average_pair_correlation_results(g_R, species) + return g_R + + else: + if not (isinstance(species, jnp.ndarray) and is_integer(species)): + raise TypeError("Malformed species; expecting array of integers.") + species_types = jnp.unique(species) + + def g_fn(R): + dim = R.shape[-1] + g_R = [] + mask = 1 - jnp.eye(R.shape[0], dtype=R.dtype) + for s in species_types: + Rs = R[species == s] + mask_s = mask[:, species == s, jnp.newaxis] + g_R += [jnp.sum(mask_s * pairwise(d(Rs, R), dim), axis=(1,))] + if compute_average: + g_R = average_pair_correlation_results(g_R, species) + return g_R + + return g_fn + + +def pair_correlation_neighbor_list( + displacement_or_metric: Union[DisplacementFn, MetricFn], + box_size: Box, + radii: Array, + sigma: float, + species: Array = None, + dr_threshold: float = 0.5, + eps: float = 1e-7, + fractional_coordinates: bool = False, + format: partition.NeighborListFormat = partition.Dense, + compute_average: bool = False, +): + """Computes the pair correlation function at a mesh of distances. + + The pair correlation function measures the number of particles at a given + distance from a central particle. The pair correlation function is defined by + + .. math:: + g(r) = <\sum_{i \\neq j}\delta(r - |r_i - r_j|)> + + We make the approximation, + + .. math:: + \delta(r) \\approx {1 \over \sqrt{2\pi\sigma^2}e^{-r / (2\sigma^2)}} + + This function uses neighbor lists to speed up the calculation. + + Args: + displacement_or_metric: A function that computes the displacement or + distance between two points. + box_size: The size of the box containing the particles. + radii: An array of radii at which we would like to compute :math:`g(r)`. + sigima: A float specifying the width of the approximating Gaussian. + species: An optional array specifying the species of each particle. If + species is None then we compute a single :math:`g(r)` for all particles, + otherwise we compute one :math:`g(r)` for each species. + dr_threshold: A float specifying the halo size of the neighbor list. + eps: A small additive constant used to ensure stability if the radius is + zero. + fractional_coordinates: Bool determining whether positions are stored in + the unit cube or not. + format: The format of the neighbor lists. Must be `Dense` or `Sparse`. + + Returns: + A pair of functions: `neighbor_fn` that constructs a neighbor list (see + `neighbor_list` in `partition.py` for details). `g_fn` that computes the + pair correlation function for a collection of particles given their + position and a neighbor list. + + :math:`g(r)` is calculated separately for each particle. For species=None, the + output of `g_fn` is an array of shape (N, nr), where N is the number of + particles passed to `g_fn` and nr is the size of radii (the number of points + at which we calculate :math:`g(r)`. When species is specified, the output is a + list of nspecies arrays, each of shape (N, nr), where nspecies is the number + of unique species. If `gofr` is the output of `g_fn`, then gofr[si][i] gives + the :math:`g(r)` for particle i considering only pair particles of species si. + + Note: when species is specified, the returned list is in the order of the + sorted unique species indices, not the order in which they appear. + """ + metric = space.canonicalize_displacement_or_metric(displacement_or_metric) + inv_rad = 1 / (radii + eps) + + def pairwise(dr, dim): + return jnp.exp(-f32(0.5) * (dr - radii) ** 2 / sigma**2) * inv_rad ** (dim - 1) + + neighbor_fn = partition.neighbor_list( + displacement_or_metric, + box_size, + jnp.max(radii) + sigma, + dr_threshold, + format=format, + ) + + if species is None: + + def g_fn(R, neighbor): + N, dim = R.shape + mask = partition.neighbor_list_mask(neighbor) + if neighbor.format is partition.Dense: + R_neigh = R[neighbor.idx] + d = space.map_neighbor(metric) + _pairwise = vmap(vmap(pairwise, (0, None)), (0, None)) + g_R = jnp.sum(mask[:, :, None] * _pairwise(d(R, R_neigh), dim), axis=(1,)) + if compute_average: + g_R = average_pair_correlation_results(g_R, species) + return g_R + elif neighbor.format is partition.Sparse: + dr = space.map_bond(metric)(R[neighbor.idx[0]], R[neighbor.idx[1]]) + _pairwise = vmap(pairwise, (0, None)) + g_R = ops.segment_sum( + mask[:, None] * _pairwise(dr, dim), neighbor.idx[0], N + ) + if compute_average: + g_R = average_pair_correlation_results(g_R, species) + return g_R + else: + raise NotImplementedError( + "Pair correlation function does not support " + "OrderedSparse neighbor lists." + ) + + else: + if not (isinstance(species, jnp.ndarray) and is_integer(species)): + raise TypeError("Malformed species; expecting array of integers.") + species_types = jnp.unique(species) + + def g_fn(R, neighbor): + N, dim = R.shape + g_R = [] + mask = partition.neighbor_list_mask(neighbor) + if neighbor.format is partition.Dense: + neighbor_species = species[neighbor.idx] + R_neigh = R[neighbor.idx] + d = space.map_neighbor(metric) + _pairwise = vmap(vmap(pairwise, (0, None)), (0, None)) + for s in species_types: + mask_s = mask * (neighbor_species == s) + g_R += [ + jnp.sum( + mask_s[:, :, jnp.newaxis] * _pairwise(d(R, R_neigh), dim), + axis=(1,), + ) + ] + elif neighbor.format is partition.Sparse: + neighbor_species = species[neighbor.idx[1]] + dr = space.map_bond(metric)(R[neighbor.idx[0]], R[neighbor.idx[1]]) + _pairwise = vmap(pairwise, (0, None)) + for s in species_types: + mask_s = mask * (neighbor_species == s) + g_R += [ + ops.segment_sum( + mask_s[:, None] * _pairwise(dr, dim), neighbor.idx[0], N + ) + ] + else: + raise NotImplementedError( + "Pair correlation function does not support " + "OrderedSparse neighbor lists." + ) + + if compute_average: + g_R = average_pair_correlation_results(g_R, species) + return g_R + + return neighbor_fn, g_fn + + +def nball_unit_volume(spatial_dimension: int) -> float: + """Return the volume of a unit sphere in arbitrary dimensions""" + return jnp.power(jnp.pi, spatial_dimension / 2) / jnp.exp( + gammaln(spatial_dimension / 2 + 1) + ) + + +def particle_volume( + radii: Array, spatial_dimension: int, particle_count: Array = 1, species: Array = None +) -> float: + """Calculate the volume of a collection of particles + + Args: + radii: array of shape (n,) giving particle radii, where n can be 1, the + number of species, or the number of particles depending on the values of + particle_count and species. + spatial_dimension: int giving the spatial dimension + particle_count: number of particles with each radii. Broadcastable to radii. + species: list of particle species. If provided, this overrides + particle_count and radii is expected to give per-species radii + + Returns: the sum of the volume of all the particles + """ + V_unit = nball_unit_volume(spatial_dimension) + V_particle = V_unit * radii**spatial_dimension + + if species is not None: + particle_count = jnp.bincount(species) + + return jnp.sum(particle_count * V_particle) + + +def volume_fraction( + box: Box, + radii: Array, + spatial_dimension: int, + particle_count: Array = 1, + species: Array = None, +) -> float: + """Calculate the volume fraction + + See documentation for particle_volume for explanation of parameters + """ + Vparticle = particle_volume(radii, spatial_dimension, particle_count, species) + return Vparticle / volume(spatial_dimension, box) + + +def box_size_at_volume_fraction( + volume_fraction: float, + radii: Array, + spatial_dimension: int, + particle_count: Array = 1, + species: Array = None, +) -> float: + """Calculate box_size to obtain a desired volume fraction + + See documentation for particle_volume for explanation of parameters + """ + Vparticle = particle_volume(radii, spatial_dimension, particle_count, species) + return jnp.power(Vparticle / volume_fraction, 1 / spatial_dimension) + + +def box_size_at_number_density( + particle_count: int, number_density: float, spatial_dimension: int +) -> float: + return jnp.power(particle_count / number_density, 1 / spatial_dimension) + + +def box_from_parameters( + a: float, b: float, c: float, alpha: float, beta: float, gamma: float +) -> Box: + alpha = alpha * jnp.pi / 180 + beta = beta * jnp.pi / 180 + gamma = gamma * jnp.pi / 180 + yy = b * jnp.sin(gamma) + xy = b * jnp.cos(gamma) + xz = c * jnp.cos(beta) + yz = (b * c * jnp.cos(alpha) - xy * xz) / yy + zz = jnp.sqrt(c**2 - xz**2 - yz**2) + return jnp.array([[a, xy, xz], [0, yy, yz], [0, 0, zz]]) + + +def bulk_modulus(elastic_tensor: Array) -> float: + return jnp.einsum("iijj->", elastic_tensor) / elastic_tensor.shape[0] ** 2 + + +@dataclasses.dataclass +class PHopState: + position_buffer: jnp.ndarray + phop: jnp.ndarray + + +InitFn = Callable[[Array], PHopState] +ApplyFn = Callable[[PHopState, Array], PHopState] +PHopCalculator = Tuple[InitFn, ApplyFn] + + +def phop(displacement: DisplacementFn, window_size: int) -> PHopCalculator: + """Computes the phop indicator of rearrangements. + + phop is an indicator function that is effective at detecting when particles + in a quiescent system have experienced a rearrangement. Qualitatively, phop + measures when the average position of a particle has changed significantly. + + Formally, given a window of size :math:`\Delta t` we two averages before and after + the current time, + + .. math:: + E_A[f] = E_{t\in[t - \Delta t / 2, t]}[f(t)] + E_B[f] = E_{t\in[t, t + \Delta t / 2]}[f(t)]. + + In terms of these expectations, phop is given by, + + .. math:: + phop = \sqrt{E_A[(R_i(t) - E_B[R_i(t)])^2]E_B[(R_i(t) - E_A[R_i(t)])^2]} + + phop was first introduced in Candelier et al. [#candelier]_ + + Args: + displacement: A function that computes displacements between pairs of + particles. See `spaces.py` for details. + window_size: An integer specifying the number of positions that constitute + the window. + + Returns: + A pair of functions, `(init_fn, update_fn)` that initialize the state of a + phop measurement and update the state of a phop measurement to include new + positions. + + .. rubric:: References + .. [#candelier] R. Candelier et al. + "Spatiotemporal Hierarchy of Relaxation Events, Dynamical Heterogeneities, + and Structural Reorganization in a Supercooled Liquid" + Physical Review Letters 105, 135702 (2010). + """ + + half_window_size = window_size // 2 + displacement = space.map_bond(displacement) + + def init_fn(position: Array) -> PHopState: + position_buffer = jnp.tile(position, (window_size, 1, 1)) + assert position_buffer.shape == ((window_size,) + position.shape) + return PHopState( + position_buffer, jnp.zeros((position.shape[0],)) + ) # pytype: disable=wrong-arg-count + + def update_fn(state: PHopState, position: Array) -> PHopState: + # Compute phop. + a_pos = state.position_buffer[:half_window_size] + a_mean = jnp.mean(a_pos, axis=0) + b_pos = state.position_buffer[half_window_size:] + b_mean = jnp.mean(b_pos, axis=0) + + phop = jnp.sqrt( + jnp.mean((a_pos - b_mean) ** 2 * (b_pos - a_mean) ** 2, axis=(0, 2)) + ) + + # Unwrap position. + buff = state.position_buffer + position = displacement(position, buff[-1]) + buff[-1] + + # Add position to the list. + buff = jnp.concatenate((buff, position[jnp.newaxis, :, :]))[1:] + + return PHopState(buff, phop) # pytype: disable=wrong-arg-count + + return init_fn, update_fn diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index af78543e..e3c2ed3e 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -10,4 +10,1686 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. \ No newline at end of file +# limitations under the License. + +"""Code to simulate systems in various statistical ensembles. + + This file contains a number of different methods that can be used to + simulate systems in a variety of ensembles. + + In general, simulation code follows the same overall structure as optimizers + in JAX. Simulations are tuples of two functions: + + init_fn: + Function that initializes the state of a system. Should take + positions as an ndarray of shape `[n, output_dimension]`. Returns a state + which will be a namedtuple. + apply_fn: + Function that takes a state and produces a new state after one + step of optimization. + + One question that we need to think about is whether the simulations should + also return a function that computes the invariant for that ensemble. This + can be used for testing purposes, but is not often used otherwise. +""" + +from collections import namedtuple + +from typing import Any, Callable, TypeVar, Union, Tuple, Dict, Optional + +import functools + +from jax import grad +from jax import jit +from jax import random +import jax.numpy as jnp +from jax import lax +from jax.tree_util import tree_map, tree_reduce, tree_flatten, tree_unflatten + +from apax.utils.jax_md_reduced import quantity +from apax.utils.jax_md_reduced import util +from apax.utils.jax_md_reduced import space +from apax.utils.jax_md_reduced import dataclasses +from apax.utils.jax_md_reduced import partition +from apax.utils.jax_md_reduced import smap + +static_cast = util.static_cast + + +# Types + + +Array = util.Array +f32 = util.f32 +f64 = util.f64 + +Box = space.Box + +ShiftFn = space.ShiftFn + +T = TypeVar("T") +InitFn = Callable[..., T] +ApplyFn = Callable[[T], T] +Simulator = Tuple[InitFn, ApplyFn] + + +"""Dispatch By State Code. + +JAX MD allows for simulations to be extensible using a dispatch strategy where +functions are dispatched to specific cases based on the type of state provided. +In particular, we make decisions about which function to call based on the type +of the position argument. For those familiar with C / C++, our dispatch code is +essentially function overloading based on the type of the positions. + +If you are interested in setting up a simulation using a different type of +system you can do so in a relatively light weight manner by introducing a new +type for storing the state that is compatible with the JAX PyTree system +(we usually choose a dataclass) and then overriding the functions below. + +These extensions allow a range of simulations to be run by just changing the +type of the position argument. There are essentially two types of functions to +be overloaded. Functions that compute physical quantities, such as the kinetic +energy, and functions that evolve a state according to the Suzuki-Trotter +decomposition. Specifically, one might want to override the position step, +momentum step for deterministic and stochastic simulations or the +`stochastic_step` for stochastic simulations (e.g Langevin). +""" + + +class dispatch_by_state: + """Wrap a function and dispatch based on the type of positions.""" + + def __init__(self, fn): + self._fn = fn + self._registry = {} + + def __call__(self, state, *args, **kwargs): + if type(state.position) in self._registry: + return self._registry[type(state.position)](state, *args, **kwargs) + return self._fn(state, *args, **kwargs) + + def register(self, oftype): + def register_fn(fn): + self._registry[oftype] = fn + + return register_fn + + +@dispatch_by_state +def canonicalize_mass(state: T) -> T: + """Reshape mass vector for broadcasting with positions.""" + + def canonicalize_fn(mass): + if isinstance(mass, float): + return mass + if mass.ndim == 2 and mass.shape[1] == 1: + return mass + elif mass.ndim == 1: + return jnp.reshape(mass, (mass.shape[0], 1)) + elif mass.ndim == 0: + return mass + msg = ( + "Expected mass to be either a floating point number or a one-dimensional" + "ndarray. Found {}.".format(mass) + ) + raise ValueError(msg) + + return state.set(mass=tree_map(canonicalize_fn, state.mass)) + + +@dispatch_by_state +def initialize_momenta(state: T, key: Array, kT: float) -> T: + """Initialize momenta with the Maxwell-Boltzmann distribution.""" + R, mass = state.position, state.mass + + R, treedef = tree_flatten(R) + mass, _ = tree_flatten(mass) + keys = random.split(key, len(R)) + + def initialize_fn(k, r, m): + p = jnp.sqrt(m * kT) * random.normal(k, r.shape, dtype=r.dtype) + # If simulating more than one particle, center the momentum. + if r.shape[0] > 1: + p = p - jnp.mean(p, axis=0, keepdims=True) + return p + + P = [initialize_fn(k, r, m) for k, r, m in zip(keys, R, mass)] + + return state.set(momentum=tree_unflatten(treedef, P)) + + +@dispatch_by_state +def momentum_step(state: T, dt: float) -> T: + """Apply a single step of the time evolution operator for momenta.""" + assert hasattr(state, "momentum") + new_momentum = tree_map(lambda p, f: p + dt * f, state.momentum, state.force) + return state.set(momentum=new_momentum) + + +@dispatch_by_state +def position_step(state: T, shift_fn: Callable, dt: float, **kwargs) -> T: + """Apply a single step of the time evolution operator for positions.""" + if isinstance(shift_fn, Callable): + shift_fn = tree_map(lambda r: shift_fn, state.position) + new_position = tree_map( + lambda s_fn, r, p, m: s_fn(r, dt * p / m, **kwargs), + shift_fn, + state.position, + state.momentum, + state.mass, + ) + return state.set(position=new_position) + + +@dispatch_by_state +def kinetic_energy(state: T) -> Array: + """Compute the kinetic energy of a state.""" + return quantity.kinetic_energy(momentum=state.momentum, mass=state.mass) + + +@dispatch_by_state +def temperature(state: T) -> Array: + """Compute the temperature of a state.""" + return quantity.temperature(momentum=state.momentum, mass=state.mass) + + +"""Deterministic Simulations + +JAX MD includes integrators for deterministic simulations of the NVE, NVT, and +NPT ensembles. For a qualitative description of statistical physics ensembles +see the wikipedia article here: +en.wikipedia.org/wiki/Statistical_ensemble_(mathematical_physics) + +Integrators are based direct translation method outlined in the paper, + +"A Liouville-operator derived measure-preserving integrator for molecular +dynamics simulations in the isothermal–isobaric ensemble" + +M. E. Tuckerman, J. Alejandre, R. López-Rendón, A. L Jochim, and G. J. Martyna +J. Phys. A: Math. Gen. 39 5629 (2006) + +As such, we define several primitives that are generically useful in describing +simulations of this type. Namely, the velocity-Verlet integration step that is +used in the NVE and NVT simulations. We also define a general Nose-Hoover chain +primitive that is used to couple components of the system to a chain that +regulates the temperature. These primitives can be combined to construct more +interesting simulations that involve e.g. temperature gradients. +""" + + +def velocity_verlet( + force_fn: Callable[..., Array], shift_fn: ShiftFn, dt: float, state: T, **kwargs +) -> T: + """Apply a single step of velocity Verlet integration to a state.""" + dt = f32(dt) + dt_2 = f32(dt / 2) + + state = momentum_step(state, dt_2) + state = position_step(state, shift_fn, dt, **kwargs) + state = state.set(force=force_fn(state.position, **kwargs)) + state = momentum_step(state, dt_2) + + return state + + +# Constant Energy Simulations + + +@dataclasses.dataclass +class NVEState: + """A struct containing the state of an NVE simulation. + + This tuple stores the state of a simulation that samples from the + microcanonical ensemble in which the (N)umber of particles, the (V)olume, and + the (E)nergy of the system are held fixed. + + Attributes: + position: An ndarray of shape `[n, spatial_dimension]` storing the position + of particles. + momentum: An ndarray of shape `[n, spatial_dimension]` storing the momentum + of particles. + force: An ndarray of shape `[n, spatial_dimension]` storing the force + acting on particles from the previous step. + mass: A float or an ndarray of shape `[n]` containing the masses of the + particles. + """ + + position: Array + momentum: Array + force: Array + mass: Array + + @property + def velocity(self) -> Array: + return self.momentum / self.mass + + +# pylint: disable=invalid-name +def nve(energy_or_force_fn, shift_fn, dt=1e-3, **sim_kwargs): + """Simulates a system in the NVE ensemble. + + Samples from the microcanonical ensemble in which the number of particles + (N), the system volume (V), and the energy (E) are held constant. We use a + standard velocity Verlet integration scheme. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + Returns: + See above. + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + + @jit + def init_fn(key, R, kT, mass=f32(1.0), **kwargs): + force = force_fn(R, **kwargs) + state = NVEState(R, None, force, mass) + state = canonicalize_mass(state) + return initialize_momenta(state, key, kT) + + @jit + def step_fn(state, **kwargs): + _dt = kwargs.pop("dt", dt) + return velocity_verlet(force_fn, shift_fn, _dt, state, **kwargs) + + return init_fn, step_fn + + +# Constant Temperature Simulations + + +# Suzuki-Yoshida weights for integrators of different order. +# These are copied from OpenMM at +# https://github.com/openmm/openmm/blob/master/openmmapi/src/NoseHooverChain.cpp + + +SUZUKI_YOSHIDA_WEIGHTS = { + 1: [1], + 3: [0.828981543588751, -0.657963087177502, 0.828981543588751], + 5: [ + 0.2967324292201065, + 0.2967324292201065, + -0.186929716880426, + 0.2967324292201065, + 0.2967324292201065, + ], + 7: [ + 0.784513610477560, + 0.235573213359357, + -1.17767998417887, + 1.31518632068391, + -1.17767998417887, + 0.235573213359357, + 0.784513610477560, + ], +} + + +@dataclasses.dataclass +class NoseHooverChain: + """State information for a Nose-Hoover chain. + + Attributes: + position: An ndarray of shape `[chain_length]` that stores the position of + the chain. + momentum: An ndarray of shape `[chain_length]` that stores the momentum of + the chain. + mass: An ndarray of shape `[chain_length]` that stores the mass of the + chain. + tau: The desired period of oscillation for the chain. Longer periods result + is better stability but worse temperature control. + kinetic_energy: A float that stores the current kinetic energy of the + system that the chain is coupled to. + degrees_of_freedom: An integer specifying the number of degrees of freedom + that the chain is coupled to. + """ + + position: Array + momentum: Array + mass: Array + tau: Array + kinetic_energy: Array + degrees_of_freedom: int = dataclasses.static_field() + + +@dataclasses.dataclass +class NoseHooverChainFns: + initialize: Callable + half_step: Callable + update_mass: Callable + + +def nose_hoover_chain( + dt: float, chain_length: int, chain_steps: int, sy_steps: int, tau: float +) -> NoseHooverChainFns: + """Helper function to simulate a Nose-Hoover Chain coupled to a system. + + This function is used in simulations that sample from thermal ensembles by + coupling the system to one, or more, Nose-Hoover chains. We use the direct + translation method outlined in Martyna et al. [#martyna92]_ and the + Nose-Hoover chains are updated using two half steps: one at the beginning of + a simulation step and one at the end. The masses of the Nose-Hoover chains + are updated automatically to enforce a specific period of oscillation, `tau`. + Larger values of `tau` will yield systems that reach the target temperature + more slowly but are also more stable. + + As described in Martyna et al. [#martyna92]_, the Nose-Hoover chain often + evolves on a faster timescale than the rest of the simulation. Therefore, it + sometimes necessary + to integrate the chain over several substeps for each step of MD. To do this + we follow the Suzuki-Yoshida scheme. Specifically, we subdivide our chain + simulation into :math:`n_c` substeps. These substeps are further subdivided + into :math:`n_sy` steps. Each :math:`n_sy` step has length + :math:`\delta_i = \Delta t w_i / n_c` where :math:`w_i` are constants such + that :math:`\sum_i w_i = 1`. See the table of Suzuki-Yoshida weights above + for specific values. The number of substeps and the number of Suzuki-Yoshida + steps are set using the `chain_steps` and `sy_steps` arguments. + + Consequently, the Nose-Hoover chains are described by three functions: an + `init_fn` that initializes the state of the chain, a `half_step_fn` that + updates the chain for one half-step, and an `update_chain_mass_fn` that + updates the masses of the chain to enforce the correct period of oscillation. + + Note that a system can have many Nose-Hoover chains coupled to it to produce, + for example, a temperature gradient. We also note that the NPT ensemble + naturally features two chains: one that couples to the thermal degrees of + freedom and one that couples to the barostat. + + Attributes: + dt: Floating point number specifying the timescale (step size) of the + simulation. + chain_length: An integer specifying the number of particles in + the Nose-Hoover chain. + chain_steps: An integer specifying the number :math:`n_c` of outer substeps. + sy_steps: An integer specifying the number of Suzuki-Yoshida steps. This + must be either `1`, `3`, `5`, or `7`. + tau: A floating point timescale over which temperature equilibration occurs. + Measured in units of `dt`. The performance of the Nose-Hoover chain + thermostat can be quite sensitive to this choice. + Returns: + A triple of functions that initialize the chain, do a half step of + simulation, and update the chain masses respectively. + """ + + def init_fn(degrees_of_freedom, KE, kT): + xi = jnp.zeros(chain_length, KE.dtype) + p_xi = jnp.zeros(chain_length, KE.dtype) + + Q = kT * tau ** f32(2) * jnp.ones(chain_length, dtype=f32) + Q = Q.at[0].multiply(degrees_of_freedom) + return NoseHooverChain(xi, p_xi, Q, tau, KE, degrees_of_freedom) + + def substep_fn(delta, P, state, kT): + """Apply a single update to the chain parameters and rescales velocity.""" + xi, p_xi, Q, _tau, KE, DOF = dataclasses.astuple(state) + + delta_2 = delta / f32(2.0) + delta_4 = delta_2 / f32(2.0) + delta_8 = delta_4 / f32(2.0) + + M = chain_length - 1 + + G = p_xi[M - 1] ** f32(2) / Q[M - 1] - kT + p_xi = p_xi.at[M].add(delta_4 * G) + + def backward_loop_fn(p_xi_new, m): + G = p_xi[m - 1] ** 2 / Q[m - 1] - kT + scale = jnp.exp(-delta_8 * p_xi_new / Q[m + 1]) + p_xi_new = scale * (scale * p_xi[m] + delta_4 * G) + return p_xi_new, p_xi_new + + idx = jnp.arange(M - 1, 0, -1) + _, p_xi_update = lax.scan(backward_loop_fn, p_xi[M], idx, unroll=2) + p_xi = p_xi.at[idx].set(p_xi_update) + + G = f32(2.0) * KE - DOF * kT + scale = jnp.exp(-delta_8 * p_xi[1] / Q[1]) + p_xi = p_xi.at[0].set(scale * (scale * p_xi[0] + delta_4 * G)) + + scale = jnp.exp(-delta_2 * p_xi[0] / Q[0]) + KE = KE * scale ** f32(2) + P = tree_map(lambda p: p * scale, P) + + xi = xi + delta_2 * p_xi / Q + + G = f32(2) * KE - DOF * kT + + def forward_loop_fn(G, m): + scale = jnp.exp(-delta_8 * p_xi[m + 1] / Q[m + 1]) + p_xi_update = scale * (scale * p_xi[m] + delta_4 * G) + G = p_xi_update**2 / Q[m] - kT + return G, p_xi_update + + idx = jnp.arange(M) + G, p_xi_update = lax.scan(forward_loop_fn, G, idx, unroll=2) + p_xi = p_xi.at[idx].set(p_xi_update) + p_xi = p_xi.at[M].add(delta_4 * G) + + return P, NoseHooverChain(xi, p_xi, Q, _tau, KE, DOF), kT + + def half_step_chain_fn(P, state, kT): + if chain_steps == 1 and sy_steps == 1: + P, state, _ = substep_fn(dt, P, state, kT) + return P, state + + delta = dt / chain_steps + ws = jnp.array(SUZUKI_YOSHIDA_WEIGHTS[sy_steps]) + + def body_fn(cs, i): + d = f32(delta * ws[i % sy_steps]) + return substep_fn(d, *cs), 0 + + P, state, _ = lax.scan( + body_fn, (P, state, kT), jnp.arange(chain_steps * sy_steps) + )[0] + return P, state + + def update_chain_mass_fn(state, kT): + xi, p_xi, Q, _tau, KE, DOF = dataclasses.astuple(state) + + Q = kT * _tau ** f32(2) * jnp.ones(chain_length, dtype=f32) + Q = Q.at[0].multiply(DOF) + + return NoseHooverChain(xi, p_xi, Q, _tau, KE, DOF) + + return NoseHooverChainFns(init_fn, half_step_chain_fn, update_chain_mass_fn) + + +def default_nhc_kwargs(tau: float, overrides: Dict) -> Dict: + default_kwargs = {"chain_length": 3, "chain_steps": 2, "sy_steps": 3, "tau": tau} + + if overrides is None: + return default_kwargs + + return {key: overrides.get(key, default_kwargs[key]) for key in default_kwargs} + + +@dataclasses.dataclass +class NVTNoseHooverState: + """State information for an NVT system with a Nose-Hoover chain thermostat. + + Attributes: + position: The current position of particles. An ndarray of floats + with shape `[n, spatial_dimension]`. + momentum: The momentum of particles. An ndarray of floats + with shape `[n, spatial_dimension]`. + force: The current force on the particles. An ndarray of floats with shape + `[n, spatial_dimension]`. + mass: The mass of the particles. Can either be a float or an ndarray + of floats with shape `[n]`. + chain: The variables describing the Nose-Hoover chain. + """ + + position: Array + momentum: Array + force: Array + mass: Array + chain: NoseHooverChain + + @property + def velocity(self): + return self.momentum / self.mass + + +def nvt_nose_hoover( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + chain_length: int = 5, + chain_steps: int = 2, + sy_steps: int = 3, + tau: Optional[float] = None, + **sim_kwargs, +) -> Simulator: + """Simulation in the NVT ensemble using a Nose Hoover Chain thermostat. + + Samples from the canonical ensemble in which the number of particles (N), + the system volume (V), and the temperature (T) are held constant. We use a + Nose Hoover Chain (NHC) thermostat described in [#martyna92]_ [#martyna98]_ + [#tuckerman]_. We follow the direct translation method outlined in + Tuckerman et al. [#tuckerman]_ and the interested reader might want to look + at that paper as a reference. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + chain_length: An integer specifying the number of particles in + the Nose-Hoover chain. + chain_steps: An integer specifying the number, :math:`n_c`, of outer + substeps. + sy_steps: An integer specifying the number of Suzuki-Yoshida steps. This + must be either `1`, `3`, `5`, or `7`. + tau: A floating point timescale over which temperature equilibration + occurs. Measured in units of `dt`. The performance of the Nose-Hoover + chain thermostat can be quite sensitive to this choice. + Returns: + See above. + + .. rubric:: References + .. [#martyna92] Martyna, Glenn J., Michael L. Klein, and Mark Tuckerman. + "Nose-Hoover chains: The canonical ensemble via continuous dynamics." + The Journal of chemical physics 97, no. 4 (1992): 2635-2643. + .. [#martyna98] Martyna, Glenn, Mark Tuckerman, Douglas J. Tobias, and Michael L. Klein. + "Explicit reversible integrators for extended systems dynamics." + Molecular Physics 87. (1998) 1117-1157. + .. [#tuckerman] Tuckerman, Mark E., Jose Alejandre, Roberto Lopez-Rendon, + Andrea L. Jochim, and Glenn J. Martyna. + "A Liouville-operator derived measure-preserving integrator for molecular + dynamics simulations in the isothermal-isobaric ensemble." + Journal of Physics A: Mathematical and General 39, no. 19 (2006): 5629. + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + dt = f32(dt) + dt_2 = f32(dt / 2) + if tau is None: + tau = dt * 100 + tau = f32(tau) + + thermostat = nose_hoover_chain(dt, chain_length, chain_steps, sy_steps, tau) + + @jit + def init_fn(key, R, mass=f32(1.0), **kwargs): + _kT = kT if "kT" not in kwargs else kwargs["kT"] + + dof = quantity.count_dof(R) + + state = NVTNoseHooverState(R, None, force_fn(R, **kwargs), mass, None) + state = canonicalize_mass(state) + state = initialize_momenta(state, key, _kT) + KE = kinetic_energy(state) + return state.set(chain=thermostat.initialize(dof, KE, _kT)) + + @jit + def apply_fn(state, **kwargs): + _kT = kT if "kT" not in kwargs else kwargs["kT"] + + chain = state.chain + + chain = thermostat.update_mass(chain, _kT) + + p, chain = thermostat.half_step(state.momentum, chain, _kT) + state = state.set(momentum=p) + + state = velocity_verlet(force_fn, shift_fn, dt, state, **kwargs) + + chain = chain.set(kinetic_energy=kinetic_energy(state)) + + p, chain = thermostat.half_step(state.momentum, chain, _kT) + state = state.set(momentum=p, chain=chain) + + return state + + return init_fn, apply_fn + + +def nvt_nose_hoover_invariant( + energy_fn: Callable[..., Array], state: NVTNoseHooverState, kT: float, **kwargs +) -> float: + """The conserved quantity for the NVT ensemble with a Nose-Hoover thermostat. + + This function is normally used for debugging the Nose-Hoover thermostat. + + Arguments: + energy_fn: The energy function of the Nose-Hoover system. + state: The current state of the system. + kT: The current goal temperature of the system. + + Returns: + The Hamiltonian of the extended NVT dynamics. + """ + PE = energy_fn(state.position, **kwargs) + KE = kinetic_energy(state) + + DOF = quantity.count_dof(state.position) + E = PE + KE + + c = state.chain + + E += c.momentum[0] ** 2 / (2 * c.mass[0]) + DOF * kT * c.position[0] + for r, p, m in zip(c.position[1:], c.momentum[1:], c.mass[1:]): + E += p**2 / (2 * m) + kT * r + return E + + +@dataclasses.dataclass +class NPTNoseHooverState: + """State information for an NPT system with Nose-Hoover chain thermostats. + + Attributes: + position: The current position of particles. An ndarray of floats + with shape `[n, spatial_dimension]`. + momentum: The velocity of particles. An ndarray of floats + with shape `[n, spatial_dimension]`. + force: The current force on the particles. An ndarray of floats with shape + `[n, spatial_dimension]`. + mass: The mass of the particles. Can either be a float or an ndarray + of floats with shape `[n]`. + reference_box: A box used to measure relative changes to the simulation + environment. + box_position: A positional degree of freedom used to describe the current + box. box_position is parameterized as `box_position = (1/d)log(V/V_0)` + where `V` is the current volume, `V_0` is the reference volume, and `d` + is the spatial dimension. + box_velocity: A velocity degree of freedom for the box. + box_mass: The mass assigned to the box. + barostat: The variables describing the Nose-Hoover chain coupled to the + barostat. + thermostsat: The variables describing the Nose-Hoover chain coupled to the + thermostat. + """ + + position: Array + momentum: Array + force: Array + mass: Array + + reference_box: Box + + box_position: Array + box_momentum: Array + box_mass: Array + + barostat: NoseHooverChain + thermostat: NoseHooverChain + + @property + def velocity(self) -> Array: + return self.momentum / self.mass + + @property + def box(self) -> Array: + """Get the current box from an NPT simulation.""" + dim = self.position.shape[1] + ref = self.reference_box + V_0 = quantity.volume(dim, ref) + V = V_0 * jnp.exp(dim * self.box_position) + return (V / V_0) ** (1 / dim) * ref + + +def _npt_box_info(state: NPTNoseHooverState) -> Tuple[float, Callable[[float], float]]: + """Gets the current volume and a function to compute the box from volume.""" + dim = state.position.shape[1] + ref = state.reference_box + V_0 = quantity.volume(dim, ref) + V = V_0 * jnp.exp(dim * state.box_position) + return V, lambda V: (V / V_0) ** (1 / dim) * ref + + +def npt_box(state: NPTNoseHooverState) -> Box: + """Get the current box from an NPT simulation.""" + dim = state.position.shape[1] + ref = state.reference_box + V_0 = quantity.volume(dim, ref) + V = V_0 * jnp.exp(dim * state.box_position) + return (V / V_0) ** (1 / dim) * ref + + +def npt_nose_hoover( + energy_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + pressure: float, + kT: float, + barostat_kwargs: Optional[Dict] = None, + thermostat_kwargs: Optional[Dict] = None, +) -> Simulator: + """Simulation in the NPT ensemble using a pair of Nose Hoover Chains. + + Samples from the canonical ensemble in which the number of particles (N), + the system pressure (P), and the temperature (T) are held constant. + We use a pair of Nose Hoover Chains (NHC) described in + [#martyna92]_ [#martyna98]_ [#tuckerman]_ coupled to the + barostat and the thermostat respectively. We follow the direct translation + method outlined in Tuckerman et al. [#tuckerman]_ and the interested reader + might want to look at that paper as a reference. + + Args: + energy_fn: A function that produces either an energy from a set of particle + positions specified as an ndarray of shape `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. Both + `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + pressure: Floating point number specifying the target pressure. To update + the pressure dynamically during a simulation one should pass `pressure` + as a keyword argument to the step function. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + barostat_kwargs: A dictionary of keyword arguments passed to the barostat + NHC. Any parameters not set are drawn from a relatively robust default + set. + thermostat_kwargs: A dictionary of keyword arguments passed to the + thermostat NHC. Any parameters not set are drawn from a relatively robust + default set. + + Returns: + See above. + + """ + + t = f32(dt) + dt_2 = f32(dt / 2) + + force_fn = quantity.force(energy_fn) + + barostat_kwargs = default_nhc_kwargs(1000 * dt, barostat_kwargs) + barostat = nose_hoover_chain(dt, **barostat_kwargs) + + thermostat_kwargs = default_nhc_kwargs(100 * dt, thermostat_kwargs) + thermostat = nose_hoover_chain(dt, **thermostat_kwargs) + + def init_fn(key, R, box, mass=f32(1.0), **kwargs): + N, dim = R.shape + + _kT = kT if "kT" not in kwargs else kwargs["kT"] + + # The box position is defined via pos = (1 / d) log V / V_0. + zero = jnp.zeros((), dtype=R.dtype) + one = jnp.ones((), dtype=R.dtype) + box_position = zero + box_momentum = zero + box_mass = dim * (N + 1) * kT * barostat_kwargs["tau"] ** 2 * one + KE_box = quantity.kinetic_energy(momentum=box_momentum, mass=box_mass) + + if jnp.isscalar(box) or box.ndim == 0: + # TODO(schsam): This is necessary because of JAX issue #5849. + box = jnp.eye(R.shape[-1]) * box + + state = NPTNoseHooverState( + R, + None, + force_fn(R, box=box, **kwargs), + mass, + box, + box_position, + box_momentum, + box_mass, + barostat.initialize(1, KE_box, _kT), + None, + ) # pytype: disable=wrong-arg-count + state = canonicalize_mass(state) + state = initialize_momenta(state, key, _kT) + KE = kinetic_energy(state) + return state.set(thermostat=thermostat.initialize(quantity.count_dof(R), KE, _kT)) + + def update_box_mass(state, kT): + N, dim = state.position.shape + dtype = state.position.dtype + box_mass = jnp.array(dim * (N + 1) * kT * state.barostat.tau**2, dtype) + return state.set(box_mass=box_mass) + + def box_force( + alpha, vol, box_fn, position, momentum, mass, force, pressure, **kwargs + ): + N, dim = position.shape + + def U(eps): + return energy_fn(position, box=box_fn(vol), perturbation=(1 + eps), **kwargs) + + dUdV = grad(U) + KE2 = util.high_precision_sum(momentum**2 / mass) + + return alpha * KE2 - dUdV(0.0) - pressure * vol * dim + + def sinhx_x(x): + """Taylor series for sinh(x) / x as x -> 0.""" + return ( + 1 + + x**2 / 6 + + x**4 / 120 + + x**6 / 5040 + + x**8 / 362_880 + + x**10 / 39_916_800 + ) + + def exp_iL1(box, R, V, V_b, **kwargs): + x = V_b * dt + x_2 = x / 2 + sinhV = sinhx_x(x_2) # jnp.sinh(x_2) / x_2 + return shift_fn( + R, R * (jnp.exp(x) - 1) + dt * V * jnp.exp(x_2) * sinhV, box=box, **kwargs + ) # pytype: disable=wrong-keyword-args + + def exp_iL2(alpha, P, F, V_b): + x = alpha * V_b * dt_2 + x_2 = x / 2 + sinhP = sinhx_x(x_2) # jnp.sinh(x_2) / x_2 + return P * jnp.exp(-x) + dt_2 * F * sinhP * jnp.exp(-x_2) + + def inner_step(state, **kwargs): + _pressure = kwargs.pop("pressure", pressure) + + R, P, M, F = state.position, state.momentum, state.mass, state.force + R_b, P_b, M_b = state.box_position, state.box_momentum, state.box_mass + + N, dim = R.shape + + vol, box_fn = _npt_box_info(state) + + alpha = 1 + 1 / N + G_e = box_force(alpha, vol, box_fn, R, P, M, F, _pressure, **kwargs) + P_b = P_b + dt_2 * G_e + P = exp_iL2(alpha, P, F, P_b / M_b) + + R_b = R_b + P_b / M_b * dt + state = state.set(box_position=R_b) + + vol, box_fn = _npt_box_info(state) + + box = box_fn(vol) + R = exp_iL1(box, R, P / M, P_b / M_b) + F = force_fn(R, box=box, **kwargs) + + P = exp_iL2(alpha, P, F, P_b / M_b) + G_e = box_force(alpha, vol, box_fn, R, P, M, F, _pressure, **kwargs) + P_b = P_b + dt_2 * G_e + + return state.set( + position=R, + momentum=P, + mass=M, + force=F, + box_position=R_b, + box_momentum=P_b, + box_mass=M_b, + ) + + def apply_fn(state, **kwargs): + S = state + _kT = kT if "kT" not in kwargs else kwargs["kT"] + + bc = barostat.update_mass(S.barostat, _kT) + tc = thermostat.update_mass(S.thermostat, _kT) + S = update_box_mass(S, _kT) + + P_b, bc = barostat.half_step(S.box_momentum, bc, _kT) + P, tc = thermostat.half_step(S.momentum, tc, _kT) + + S = S.set(momentum=P, box_momentum=P_b) + S = inner_step(S, **kwargs) + + KE = quantity.kinetic_energy(momentum=S.momentum, mass=S.mass) + tc = tc.set(kinetic_energy=KE) + + KE_box = quantity.kinetic_energy(momentum=S.box_momentum, mass=S.box_mass) + bc = bc.set(kinetic_energy=KE_box) + + P, tc = thermostat.half_step(S.momentum, tc, _kT) + P_b, bc = barostat.half_step(S.box_momentum, bc, _kT) + + S = S.set(thermostat=tc, barostat=bc, momentum=P, box_momentum=P_b) + + return S + + return init_fn, apply_fn + + +def npt_nose_hoover_invariant( + energy_fn: Callable[..., Array], + state: NPTNoseHooverState, + pressure: float, + kT: float, + **kwargs, +) -> float: + """The conserved quantity for the NPT ensemble with a Nose-Hoover thermostat. + + This function is normally used for debugging the NPT simulation. + + Arguments: + energy_fn: The energy function of the system. + state: The current state of the system. + pressure: The current goal pressure of the system. + kT: The current goal temperature of the system. + + Returns: + The Hamiltonian of the extended NPT dynamics. + """ + volume, box_fn = _npt_box_info(state) + PE = energy_fn(state.position, box=box_fn(volume), **kwargs) + KE = kinetic_energy(state) + + DOF = state.position.size + E = PE + KE + + c = state.thermostat + E += c.momentum[0] ** 2 / (2 * c.mass[0]) + DOF * kT * c.position[0] + for r, p, m in zip(c.position[1:], c.momentum[1:], c.mass[1:]): + E += p**2 / (2 * m) + kT * r + + c = state.barostat + for r, p, m in zip(c.position, c.momentum, c.mass): + E += p**2 / (2 * m) + kT * r + + E += pressure * volume + E += state.box_momentum**2 / (2 * state.box_mass) + + return E + + +"""Stochastic Simulations + +JAX MD includes integrators for stochastic simulations of Langevin dynamics and +Brownian motion for systems in the NVT ensemble with a solvent. +""" + + +@dataclasses.dataclass +class Normal: + """A simple normal distribution.""" + + mean: jnp.ndarray + var: jnp.ndarray + + def sample(self, key): + mu, sigma = self.mean, jnp.sqrt(self.var) + return mu + sigma * random.normal(key, mu.shape, dtype=mu.dtype) + + def log_prob(self, x): + return ( + -0.5 * jnp.log(2 * jnp.pi * self.var) + - 1 / (2 * self.var) * (x - self.mean) ** 2 + ) + + +@dataclasses.dataclass +class NVTLangevinState: + """A struct containing state information for the Langevin thermostat. + + Attributes: + position: The current position of the particles. An ndarray of floats with + shape `[n, spatial_dimension]`. + momentum: The momentum of particles. An ndarray of floats with shape + `[n, spatial_dimension]`. + force: The (non-stochastic) force on particles. An ndarray of floats with + shape `[n, spatial_dimension]`. + mass: The mass of particles. Will either be a float or an ndarray of floats + with shape `[n]`. + rng: The current state of the random number generator. + """ + + position: Array + momentum: Array + force: Array + mass: Array + rng: Array + + @property + def velocity(self) -> Array: + return self.momentum / self.mass + + +@dispatch_by_state +def stochastic_step(state: NVTLangevinState, dt: float, kT: float, gamma: float): + """A single stochastic step (the `O` step).""" + c1 = jnp.exp(-gamma * dt) + c2 = jnp.sqrt(kT * (1 - c1**2)) + momentum_dist = Normal(c1 * state.momentum, c2**2 * state.mass) + key, split = random.split(state.rng) + return state.set(momentum=momentum_dist.sample(split), rng=key) + + +def nvt_langevin( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + gamma: float = 0.1, + center_velocity: bool = True, + **sim_kwargs, +) -> Simulator: + """Simulation in the NVT ensemble using the BAOAB Langevin thermostat. + + Samples from the canonical ensemble in which the number of particles (N), + the system volume (V), and the temperature (T) are held constant. Langevin + dynamics are stochastic and it is supposed that the system is interacting + with fictitious microscopic degrees of freedom. An example of this would be + large particles in a solvent such as water. Thus, Langevin dynamics are a + stochastic ODE described by a friction coefficient and noise of a given + covariance. + + Our implementation follows the paper [#davidcheck] by Davidchack, Ouldridge, + and Tretyakov. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. Both + `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + gamma: A float specifying the friction coefficient between the particles + and the solvent. + center_velocity: A boolean specifying whether or not the center of mass + position should be subtracted. + Returns: + See above. + + .. rubric:: References + .. [#carlon] R. L. Davidchack, T. E. Ouldridge, and M. V. Tretyakov. + "New Langevin and gradient thermostats for rigid body dynamics." + The Journal of Chemical Physics 142, 144114 (2015) + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + + @jit + def init_fn(key, R, mass=f32(1.0), **kwargs): + _kT = kwargs.pop("kT", kT) + key, split = random.split(key) + force = force_fn(R, **kwargs) + state = NVTLangevinState(R, None, force, mass, key) + state = canonicalize_mass(state) + return initialize_momenta(state, split, _kT) + + @jit + def step_fn(state, **kwargs): + _dt = kwargs.pop("dt", dt) + _kT = kwargs.pop("kT", kT) + dt_2 = _dt / 2 + + state = momentum_step(state, dt_2) + state = position_step(state, shift_fn, dt_2, **kwargs) + state = stochastic_step(state, _dt, _kT, gamma) + state = position_step(state, shift_fn, dt_2, **kwargs) + state = state.set(force=force_fn(state.position, **kwargs)) + state = momentum_step(state, dt_2) + + return state + + return init_fn, step_fn + + +@dataclasses.dataclass +class BrownianState: + """A tuple containing state information for Brownian dynamics. + + Attributes: + position: The current position of the particles. An ndarray of floats with + shape `[n, spatial_dimension]`. + mass: The mass of particles. Will either be a float or an ndarray of floats + with shape `[n]`. + rng: The current state of the random number generator. + """ + + position: Array + mass: Array + rng: Array + + +def brownian( + energy_or_force: Callable[..., Array], + shift: ShiftFn, + dt: float, + kT: float, + gamma: float = 0.1, +) -> Simulator: + """Simulation of Brownian dynamics. + + Simulates Brownian dynamics which are synonymous with the overdamped + regime of Langevin dynamics. However, in this case we don't need to take into + account velocity information and the dynamics simplify. Consequently, when + Brownian dynamics can be used they will be faster than Langevin. As in the + case of Langevin dynamics our implementation follows Carlon et al. [#carlon]_ + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + gamma: A float specifying the friction coefficient between the particles + and the solvent. + + Returns: + See above. + """ + + force_fn = quantity.canonicalize_force(energy_or_force) + + dt, gamma = static_cast(dt, gamma) + + def init_fn(key, R, mass=f32(1)): + state = BrownianState(R, mass, key) + return canonicalize_mass(state) + + def apply_fn(state, **kwargs): + _kT = kT if "kT" not in kwargs else kwargs["kT"] + + R, mass, key = dataclasses.astuple(state) + + key, split = random.split(key) + + F = force_fn(R, **kwargs) + xi = random.normal(split, R.shape, R.dtype) + + nu = f32(1) / (mass * gamma) + + dR = F * dt * nu + jnp.sqrt(f32(2) * _kT * dt * nu) * xi + R = shift(R, dR, **kwargs) + + return BrownianState(R, mass, key) # pytype: disable=wrong-arg-count + + return init_fn, apply_fn + + +"""Experimental Simulations. + + +Below are simulation environments whose implementation is somewhat +experimental / preliminary. These environments might not be as ergonomic +as the more polished environments above. +""" + + +@dataclasses.dataclass +class SwapMCState: + """A struct containing state information about a Hybrid Swap MC simulation. + + Attributes: + md: A NVTNoseHooverState containing continuous molecular dynamics data. + sigma: An `[n,]` array of particle radii. + key: A JAX PRGNKey used for random number generation. + neighbor: A NeighborList for the system. + """ + + md: NVTNoseHooverState + sigma: Array + key: Array + neighbor: partition.NeighborList + + +# pytype: disable=wrong-arg-count +# pytype: disable=wrong-keyword-args +def hybrid_swap_mc( + space_fns: space.Space, + energy_fn: Callable[[Array, Array], Array], + neighbor_fn: partition.NeighborFn, + dt: float, + kT: float, + t_md: float, + N_swap: int, + sigma_fn: Optional[Callable[[Array], Array]] = None, +) -> Simulator: + """Simulation of Hybrid Swap Monte-Carlo. + + This code simulates the hybrid Swap Monte Carlo algorithm introduced in + Berthier et al. [#berthier]_ + Here an NVT simulation is performed for `t_md` time and then `N_swap` MC + moves are performed that swap the radii of randomly chosen particles. The + random swaps are accepted with Metropolis-Hastings step. Each call to the + step function runs molecular dynamics for `t_md` and then performs the swaps. + + Note that this code doesn't feature some of the convenience functions in the + other simulations. In particular, there is no support for dynamics keyword + arguments and the energy function must be a simple callable of two variables: + the distance between adjacent particles and the diameter of the particles. + If you want support for a better notion of potential or dynamic keyword + arguments, please file an issue! + + Args: + space_fns: A tuple of a displacement function and a shift function defined + in `space.py`. + energy_fn: A function that computes the energy between one pair of + particles as a function of the distance between the particles and the + diameter. This function should not have been passed to `smap.xxx`. + neighbor_fn: A function to construct neighbor lists outlined in + `partition.py`. + dt: The timestep used for the continuous time MD portion of the simulation. + kT: The temperature of heat bath that the system is coupled to during MD. + t_md: The time of each MD block. + N_swap: The number of swapping moves between MD blocks. + sigma_fn: An optional function for combining radii if they are to be + non-additive. + + Returns: + See above. + + .. rubric:: References + .. [#berthier] L. Berthier, E. Flenner, C. J. Fullerton, C. Scalliet, and M. Singh. + "Efficient swap algorithms for molecular dynamics simulations of + equilibrium supercooled liquids", J. Stat. Mech. (2019) 064004 + """ + displacement_fn, shift_fn = space_fns + metric_fn = space.metric(displacement_fn) + nbr_metric_fn = space.map_neighbor(metric_fn) + + md_steps = int(t_md // dt) + + # Canonicalize the argument names to be dr and sigma. + wrapped_energy_fn = lambda dr, sigma: energy_fn(dr, sigma) + if sigma_fn is None: + sigma_fn = lambda si, sj: 0.5 * (si + sj) + nbr_energy_fn = smap.pair_neighbor_list(wrapped_energy_fn, metric_fn, sigma=sigma_fn) + + nvt_init_fn, nvt_step_fn = nvt_nose_hoover( + nbr_energy_fn, shift_fn, dt, kT=kT, chain_length=3 + ) + + def init_fn(key, position, sigma, nbrs=None): + key, sim_key = random.split(key) + nbrs = neighbor_fn(position, nbrs) # pytype: disable=wrong-arg-count + md_state = nvt_init_fn(sim_key, position, neighbor=nbrs, sigma=sigma) + return SwapMCState(md_state, sigma, key, nbrs) # pytype: disable=wrong-arg-count + + def md_step_fn(i, state): + md, sigma, key, nbrs = dataclasses.unpack(state) + md = nvt_step_fn( + md, neighbor=nbrs, sigma=sigma + ) # pytype: disable=wrong-keyword-args + nbrs = neighbor_fn(md.position, nbrs) + return SwapMCState(md, sigma, key, nbrs) # pytype: disable=wrong-arg-count + + def swap_step_fn(i, state): + md, sigma, key, nbrs = dataclasses.unpack(state) + + N = md.position.shape[0] + + # Swap a random pair of particle radii. + key, particle_key, accept_key = random.split(key, 3) + ij = random.randint(particle_key, (2,), jnp.array(0), jnp.array(N)) + new_sigma = sigma.at[ij].set([sigma[ij[1]], sigma[ij[0]]]) + + # Collect neighborhoods around the two swapped particles. + nbrs_ij = nbrs.idx[ij] + R_ij = md.position[ij] + R_neigh = md.position[nbrs_ij] + + sigma_ij = sigma[ij][:, None] + sigma_neigh = sigma[nbrs_ij] + + new_sigma_ij = new_sigma[ij][:, None] + new_sigma_neigh = new_sigma[nbrs_ij] + + dR = nbr_metric_fn(R_ij, R_neigh) + + # Compute the energy before the swap. + energy = energy_fn(dR, sigma_fn(sigma_ij, sigma_neigh)) + energy = jnp.sum(energy * (nbrs_ij < N)) + + # Compute the energy after the swap. + new_energy = energy_fn(dR, sigma_fn(new_sigma_ij, new_sigma_neigh)) + new_energy = jnp.sum(new_energy * (nbrs_ij < N)) + + # Accept or reject with a metropolis probability. + p = random.uniform(accept_key, ()) + accept_prob = jnp.minimum(1, jnp.exp(-(new_energy - energy) / kT)) + sigma = jnp.where(p < accept_prob, new_sigma, sigma) + + return SwapMCState(md, sigma, key, nbrs) # pytype: disable=wrong-arg-count + + def block_fn(state): + state = lax.fori_loop(0, md_steps, md_step_fn, state) + state = lax.fori_loop(0, N_swap, swap_step_fn, state) + return state + + return init_fn, block_fn + + +# pytype: enable=wrong-arg-count +# pytype: enable=wrong-keyword-args + + +def temp_rescale( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + window: float, + fraction: float, + **sim_kwargs, +) -> Simulator: + """Simulation using explicit velocity rescaling. + + Rescale the velocities of atoms explicitly so that the desired temperature is + reached. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + window: Floating point number specifying the temperature window outside which + rescaling is performed. Measured in units of `kT`. + fraction: Floating point number which determines the amount of rescaling + applied to the velocities. Takes values from 0.0-1.0. + Returns: + See above. + + .. rubric:: References + .. [#berendsen84] Woodcock, L. V. + "ISOTHERMAL MOLECULAR DYNAMICS CALCULATIONS FOR LIQUID SALTS." + Chem. Phys. Lett. 1971, 10, 257–261. + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + dt = f32(dt) + + def velocity_rescale(state, window, fraction, kT): + """Rescale the momentum if the the difference between current and target + temperature is more than the window""" + kT_current = temperature(state) + cond = jnp.abs(kT_current - kT) > window + kT_target = kT_current - fraction * (kT_current - kT) + lam = jnp.where(cond, jnp.sqrt(kT_target / kT_current), 1) + new_momentum = tree_map(lambda p: p * lam, state.momentum) + return state.set(momentum=new_momentum) + + def init_fn(key, R, mass=f32(1.0), **kwargs): + # Reuse the NVEState dataclass + state = NVEState(R, None, force_fn(R, **kwargs), mass) + state = canonicalize_mass(state) + return initialize_momenta(state, key, kT) + + def apply_fn(state, **kwargs): + state = velocity_rescale(state, window, fraction, kT) + state = velocity_verlet(force_fn, shift_fn, dt, state, **kwargs) + return state + + return init_fn, apply_fn + + +def temp_berendsen( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + tau: float, + **sim_kwargs, +) -> Simulator: + """Simulation using the Berendsen thermostat. + + Berendsen (weak coupling) thermostat rescales the velocities of atoms such + that the desired temperature is reached. This rescaling is performed at each + timestep (dt) and the rescaling factor is calculated using + Eq.10 Berendsen et al. [#berendsen84]_. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + tau: A floating point number determining how fast the temperature + is relaxed during the simulation. Measured in units of `dt`. + Returns: + See above. + + .. rubric:: References + .. [#berendsen84] H. J. C. Berendsen, J. P. M. Postma, W. F. van Gunsteren, A. DiNola, J. R. Haak. + "Molecular dynamics with coupling to an external bath." + J. Chem. Phys. 15 October 1984; 81 (8): 3684-3690. + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + dt = f32(dt) + + def berendsen_update(state, tau, kT, dt): + """Rescaling the momentum of the particle by the factor lam.""" + _kT = temperature(state) + lam = jnp.sqrt(1 + ((dt / tau) * ((kT / _kT) - 1))) + new_momentum = tree_map(lambda p: p * lam, state.momentum) + return state.set(momentum=new_momentum) + + def init_fn(key, R, mass=f32(1.0), **kwargs): + # Reuse the NVEState dataclass + state = NVEState(R, None, force_fn(R, **kwargs), mass) + state = canonicalize_mass(state) + return initialize_momenta(state, key, kT) + + def apply_fn(state, **kwargs): + state = berendsen_update(state, tau, kT, dt) + state = velocity_verlet(force_fn, shift_fn, dt, state, **kwargs) + return state + + return init_fn, apply_fn + + +def nvk( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + **sim_kwargs, +) -> Simulator: + """Simulation in the NVK (isokinetic) ensemble using the Gaussian thermostat. + + Samples from the isokinetic ensemble in which the number of particles (N), + the system volume (V), and the kinetic energy (K) are held constant. A + Gaussian thermostat is used for the integration and the kinetic energy is + held constant during the simulation. The implementation follows the steps + described in [#minary2003]_ and [#zhang97]_. See section 4(B) equation + 4.12-4.17 in [#minary2003]_ for detailed description. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + Returns: + See above. + + .. rubric:: References + .. [#minary2003] Minary, Peter and Martyna, Glenn J. and Tuckerman, Mark E. + "Algorithms and novel applications based on the isokinetic ensemble. I. + Biophysical and path integral molecular dynamics" + J. Chem. Phys., Vol. 118, No. 6, 8 February 2003. + .. [#zhang97] Zhang, Fei. + "Operator-splitting integrators for constant-temperature molecular dynamics" + J. Chem. Phys. 106, 6102–6106 (1997). + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + dt = f32(dt) + dt_2 = f32(dt / 2) + + def momentum_update(state, KE): + # eps to avoid edge cases when forces are zero + eps = 1e-16 + + # Equation 4.13 to compute a and b + update_fn = lambda f, p, m: f * p / m + a = ( + util.high_precision_sum(update_fn(state.force, state.momentum, state.mass)) + + eps + ) + b = util.high_precision_sum(update_fn(state.force, state.force, state.mass)) + eps + a /= 2.0 * KE + b /= 2.0 * KE + + # Equation 4.12 to compute s(t) and s_dot(t) + b_sqrt = jnp.sqrt(b) + s_t = ((a / b) * (jnp.cosh(dt_2 * b_sqrt) - 1.0)) + jnp.sinh( + dt_2 * b_sqrt + ) / b_sqrt + s_dot_t = (b_sqrt * (a / b) * jnp.sinh(dt_2 * b_sqrt)) + jnp.cosh(dt_2 * b_sqrt) + + # Get the new momentum using Equation 4.15 + new_momentum = tree_map( + lambda p, f, s, sdot: (p + f * s) / sdot, + state.momentum, + state.force, + s_t, + s_dot_t, + ) + return state.set(momentum=new_momentum) + + def position_update(state, shift_fn, **kwargs): + if isinstance(shift_fn, Callable): + shift_fn = tree_map(lambda r: shift_fn, state.position) + # Get the new positions using Equation 4.16 (Should read r = r + dt * p / m) + new_position = tree_map( + lambda s_fn, r, v: s_fn(r, dt * v, **kwargs), + shift_fn, + state.position, + state.velocity, + ) + return state.set(position=new_position) + + def init_fn(key, R, mass=f32(1.0), **kwargs): + _kT = kwargs.pop("kT", kT) + key, split = random.split(key) + # Reuse the NVEState dataclass + state = NVEState(R, None, force_fn(R, **kwargs), mass) + state = canonicalize_mass(state) + return initialize_momenta(state, split, _kT) + + def apply_fn(state, **kwargs): + _KE = kinetic_energy(state) + state = momentum_update(state, _KE) + state = position_update(state, shift_fn) + state = state.set(force=force_fn(state.position, **kwargs)) + state = momentum_update(state, _KE) + return state + + return init_fn, apply_fn + + +def temp_csvr( + energy_or_force_fn: Callable[..., Array], + shift_fn: ShiftFn, + dt: float, + kT: float, + tau: float, + **sim_kwargs, +) -> Simulator: + """Simulation using the canonical sampling through velocity rescaling (CSVR) thermostat. + + Samples from the canonical ensemble in which the number of particles (N), + the system volume (V), and the temperature (T) are held constant. CSVR + algorithmn samples the canonical distribution by rescaling the velocities + by a appropritely chosen random factor. At each timestep (dt) the rescaling + takes place and the rescaling factor is calculated using + A7 Bussi et al. [#bussi2007]_. CSVR updates to the velocity are stochastic in + nature and unlike the Berendsen thermostat it samples the true canonical + distribution [#Braun2018]_. + + Args: + energy_or_force: A function that produces either an energy or a force from + a set of particle positions specified as an ndarray of shape + `[n, spatial_dimension]`. + shift_fn: A function that displaces positions, `R`, by an amount `dR`. + Both `R` and `dR` should be ndarrays of shape `[n, spatial_dimension]`. + dt: Floating point number specifying the timescale (step size) of the + simulation. + kT: Floating point number specifying the temperature in units of Boltzmann + constant. To update the temperature dynamically during a simulation one + should pass `kT` as a keyword argument to the step function. + tau: A floating point number determining how fast the temperature + is relaxed during the simulation. Measured in units of `dt`. + Returns: + See above. + + .. rubric:: References + .. [#bussi2007] Bussi G, Donadio D, Parrinello M. + "Canonical sampling through velocity rescaling." + The Journal of chemical physics, 126(1), 014101. + .. [#Braun2018] Efrem Braun, Seyed Mohamad Moosavi, and Berend Smit. + "Anomalous Effects of Velocity Rescaling Algorithms: The Flying Ice Cube Effect Revisited." + Journal of Chemical Theory and Computation 2018 14 (10), 5262-5272. + """ + force_fn = quantity.canonicalize_force(energy_or_force_fn) + dt = f32(dt) + + def sum_noises(state, key): + """Sum of N independent gaussian noises squared. + Adapted from https://github.com/GiovanniBussi/StochasticVelocityRescaling + For more details see Eq.A7 Bussi et al. [#bussi2007]_""" + dof = quantity.count_dof(state.position) - 1 + _dtype = state.position.dtype + + if dof == 0: + """If there are no terms return zero.""" + return 0 + + elif dof == 1: + """For a single noise term, directly calculate the square of the Gaussian + noise value.""" + rr = random.normal(key, dtype=_dtype) + return rr * rr + + elif dof % 2 == 0: + """For an even number of noise terms, use the gamma-distributed random + number generator""" + return 2.0 * random.gamma(key, dof // 2, dtype=_dtype) + + else: + """For an odd number of noise terms, sum two terms: one from the + gamma-distributed generator and another from the square of a + Gaussian-distributed random number.""" + rr = random.normal(key, dtype=_dtype) + return 2.0 * random.gamma(key, (dof - 1) // 2, dtype=_dtype) + (rr * rr) + + def csvr_update(state, tau, kT, dt): + """Update the momentum by an scaling factor as described by + Eq.A7 Bussi et al. [#bussi2007]_""" + key, split = random.split(state.rng) + dof = quantity.count_dof(state.position) + + _kT = temperature(state) + + KE_old = dof * _kT / 2 + KE_new = dof * kT / 2 + + r1 = random.normal(key, dtype=state.position.dtype) + r2 = sum_noises(state, key) + + c1 = jnp.exp(-dt / tau) + c2 = (1 - c1) * KE_new / KE_old / dof + + scale = c1 + (c2 * ((r1 * r1) + r2)) + (2 * r1 * jnp.sqrt(c1 * c2)) + lam = jnp.sqrt(scale) + + new_momentum = tree_map(lambda p: p * lam, state.momentum) + return state.set(momentum=new_momentum, rng=key) + + def init_fn(key, R, mass=f32(1.0), **kwargs): + _kT = kwargs.pop("kT", kT) + key, split = random.split(key) + # Reuse the NVTLangevinState dataclass + state = NVTLangevinState(R, None, force_fn(R, **kwargs), mass, key) + state = canonicalize_mass(state) + return initialize_momenta(state, split, _kT) + + def apply_fn(state, **kwargs): + state = csvr_update(state, tau, kT, dt) + state = velocity_verlet(force_fn, shift_fn, dt, state, **kwargs) + return state + + return init_fn, apply_fn diff --git a/apax/utils/jax_md_reduced/smap.py b/apax/utils/jax_md_reduced/smap.py new file mode 100644 index 00000000..4d30193c --- /dev/null +++ b/apax/utils/jax_md_reduced/smap.py @@ -0,0 +1,933 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Code to transform functions on individual tuples of particles to sets.""" + +from functools import reduce, partial + +from typing import Dict, Callable, List, Tuple, Union, Optional + +import math +import enum +from operator import mul + +import numpy as onp + +from jax import lax, ops, vmap, eval_shape, tree_map +from jax.core import ShapedArray +from jax.interpreters import partial_eval as pe +import jax.numpy as jnp + +from apax.utils.jax_md_reduced import dataclasses +from apax.utils.jax_md_reduced import quantity +from apax.utils.jax_md_reduced import space +from apax.utils.jax_md_reduced import util +from apax.utils.jax_md_reduced import partition + +high_precision_sum = util.high_precision_sum + +# Typing + +Array = util.Array +PyTree = util.PyTree + +f32 = util.f32 +f64 = util.f64 + +i32 = util.i32 +i64 = util.i64 + +DisplacementOrMetricFn = space.DisplacementOrMetricFn + +# Parameter Trees + + +class ParameterTreeMapping(enum.Enum): + """An enum specifying how parameters are processed in mapped functions. + + Attributes: + Global: Global parameters are passed directly to the mapped function. + PerParticle: PerParticle parameters are combined in pairs based on the + particle index. E.g. `p_ij = combinator(p_i, p_j)` for particles i and j. + These parameters are expected to have a leading axis of length the number + of particles. + PerBond: PerBond parameters are expected to have leading two dimensions + equal to the number of particles in the system. + PerSpecies: PerSpecies parameters are expected to have two leading + dimensions equal to the number of species. For particles of species `s_i` + and `s_j` parameters are combined according to + `p_ij = combinator(p[s_i], p[s_j])`. + """ + + Global = 0 + PerParticle = 1 + PerBond = 2 + PerSpecies = 3 + + +@dataclasses.dataclass +class ParameterTree: + """A container denoting that parameters are in the form of a PyTree. + + Attributes: + tree: A JAX PyTree containing a tree of parameters. Before being fed into + mapped functions, these parameters are processed according to the + mapping. + mapping: A ParameterTreeMapping object that specifies how the parameters + are processed. + """ + + tree: PyTree + mapping: ParameterTreeMapping = dataclasses.static_field() + + +Parameter = Union[ParameterTree, Array, float] + + +# Mapping potential functional forms to bonds. + + +def _get_bond_type_parameters(params: Array, bond_type: Array) -> Array: + """Get parameters for interactions for bonds indexed by a bond-type.""" + # TODO(schsam): We should do better error checking here. + assert util.is_array(bond_type) + assert len(bond_type.shape) == 1 + + if util.is_array(params): + if len(params.shape) == 1: + return params[bond_type] + elif len(params.shape) == 0: + return params + else: + raise ValueError( + "Params must be a scalar or a 1d array if using a bond-type lookup." + ) + elif isinstance(params, ParameterTree): + if params.mapping is ParameterTreeMapping.Global: + return params.tree + elif params.mapping is ParameterTreeMapping.PerBond: + return tree_map(lambda p: p[bond_type], params.tree) + else: + raise ValueError( + "ParameterTreeMapping must be either Global or PerBond" + "if used with `smap.bond`." + ) + elif ( + isinstance(params, int) + or isinstance(params, float) + or jnp.issubdtype(params, jnp.integer) + or jnp.issubdtype(params, jnp.floating) + ): + return params + raise NotImplementedError + + +def _kwargs_to_bond_parameters( + bond_type: Array, kwargs: Dict[str, Array] +) -> Dict[str, Array]: + """Extract parameters from keyword arguments.""" + # NOTE(schsam): We could pull out the species case from the generic case. + for k, v in kwargs.items(): + if bond_type is not None: + kwargs[k] = _get_bond_type_parameters(v, bond_type) + return kwargs + + +def bond( + fn: Callable[..., Array], + displacement_or_metric: DisplacementOrMetricFn, + static_bonds: Optional[Array] = None, + static_bond_types: Optional[Array] = None, + ignore_unused_parameters: bool = False, + **kwargs, +) -> Callable[..., Array]: + """Promotes a function that acts on a single pair to one on a set of bonds. + + TODO(schsam): It seems like bonds might potentially have poor memory access. + Should think about this a bit and potentially optimize. + + Args: + fn: A function that takes an ndarray of pairwise distances or displacements + of shape `[n, m]` or `[n, m, d_in]` respectively as well as kwargs + specifying parameters for the function. `fn` returns an ndarray of + evaluations of shape `[n, m, d_out]`. + metric: A function that takes two ndarray of positions of shape + `[spatial_dimension]` and `[spatial_dimension]` respectively and returns + an ndarray of distances or displacements of shape `[]` or `[d_in]` + respectively. The metric can optionally take a floating point time as a + third argument. + static_bonds: An ndarray of integer pairs wth shape `[b, 2]` where each + pair specifies a bond. `static_bonds` are baked into the returned compute + function statically and cannot be changed after the fact. + static_bond_types: An ndarray of integers of shape `[b]` specifying the + type of each bond. Only specify bond types if you want to specify bond + parameters by type. One can also specify constant or per-bond parameters + (see below). + ignore_unused_parameters: A boolean that denotes whether dynamically + specified keyword arguments passed to the mapped function get ignored + if they were not first specified as keyword arguments when calling + `smap.bond(...)`. + kwargs: Arguments providing parameters to the mapped function. In cases + where no bond type information is provided these should be either + + 1. a scalar + 2. an ndarray of shape `[b]`. + + If bond type information is provided then the parameters should be + specified as either + + 1. a scalar + 2. an ndarray of shape `[max_bond_type]`. + 3. a ParameterTree containing a PyTree of parameters and a mapping. See + ParameterTree for details. + Returns: + A function `fn_mapped`. Note that `fn_mapped` can take arguments bonds and + `bond_types` which will be bonds that are specified dynamically. This will + incur a recompilation when the number of bonds changes. Improving this + state of affairs I will leave as a TODO until someone actually uses this + feature and runs into speed issues. + """ + + # Each call to vmap adds a single batch dimension. Here, we would like to + # promote the metric function from one that computes the distance / + # displacement between two vectors to one that acts on two lists of vectors. + # Thus, we apply a single application of vmap. + + merge_dicts = partial( + util.merge_dicts, ignore_unused_parameters=ignore_unused_parameters + ) + + def compute_fn(R, bonds, bond_types, static_kwargs, dynamic_kwargs): + Ra = R[bonds[:, 0]] + Rb = R[bonds[:, 1]] + _kwargs = merge_dicts(static_kwargs, dynamic_kwargs) + _kwargs = _kwargs_to_bond_parameters(bond_types, _kwargs) + # NOTE(schsam): This pattern is needed due to JAX issue #912. + d = vmap(partial(displacement_or_metric, **dynamic_kwargs), 0, 0) + dr = d(Ra, Rb) + return high_precision_sum(fn(dr, **_kwargs)) + + def mapped_fn( + R: Array, + bonds: Optional[Array] = None, + bond_types: Optional[Array] = None, + **dynamic_kwargs, + ) -> Array: + accum = f32(0) + + if bonds is not None: + accum = accum + compute_fn(R, bonds, bond_types, kwargs, dynamic_kwargs) + + if static_bonds is not None: + accum = accum + compute_fn( + R, static_bonds, static_bond_types, kwargs, dynamic_kwargs + ) + + return accum + + return mapped_fn + + +# Mapping potential functional forms to pairwise interactions. + + +def _get_species_parameters(params: Parameter, species: Array) -> Parameter: + """Get parameters for interactions between species pairs.""" + # TODO(schsam): We should do better error checking here. + if util.is_array(params): + if len(params.shape) == 2: + return params[species] + elif len(params.shape) == 0: + return params + else: + raise ValueError( + "Params must be a scalar or a 2d array if using a species lookup." + ) + elif isinstance(params, ParameterTree): + p = params.tree + if params.mapping is ParameterTreeMapping.Global: + return p + elif params.mapping is ParameterTreeMapping.PerSpecies: + return tree_map(lambda x: x[species], p) + else: + raise ValueError( + "When species are present, ParameterTreeMapping must " + f"be Global or PerSpecies. Found {params.mapping}." + ) + return params + + +def _get_matrix_parameters( + params: Parameter, combinator: Callable[[Array, Array], Array] +) -> Parameter: + """Get an NxN parameter matrix from per-particle parameters.""" + if util.is_array(params): + if params.ndim == 1: + return combinator(params[:, jnp.newaxis], params[jnp.newaxis, :]) + elif params.ndim == 0 or params.ndim == 2: + return params + else: + raise ValueError( + "Without species information, parameters must be " + "an array of dimension 0, 1, or 2. " + f"Found {params.ndim}." + ) + elif isinstance(params, ParameterTree): + M = ParameterTreeMapping + if params.mapping in (M.Global, M.PerBond): + return params.tree + elif params.mapping is M.PerParticle: + return tree_map( + lambda p: combinator(p[:, None, ...], p[None, :, ...]), params.tree + ) + else: + raise ValueError( + "Without species information, ParameterTreeMapping " + "must be Global, PerBond, or PerParticle. " + f"Found {params.mapping}." + ) + elif ( + isinstance(params, int) + or isinstance(params, float) + or jnp.issubdtype(params, jnp.integer) + or jnp.issubdtype(params, jnp.floating) + ): + return params + else: + raise ValueError( + "Without species information, params must eitehr be an " + "array, a ParameterTree, or a float. " + f"Found {type(params)}." + ) + + +def _kwargs_to_parameters( + species: Array, kwargs: Dict[str, Parameter], combinators: Dict[str, Callable] +) -> Dict[str, Array]: + """Extract parameters from keyword arguments.""" + # NOTE(schsam): We could pull out the species case from the generic case. + s_kwargs = {} + for k, v in kwargs.items(): + if species is None: + combinator = combinators.get(k, lambda x, y: 0.5 * (x + y)) + s_kwargs[k] = _get_matrix_parameters(v, combinator) + else: + if k in combinators: + raise ValueError("Cannot specify custom combinator with species.") + s_kwargs[k] = _get_species_parameters(v, species) + return s_kwargs + + +def _diagonal_mask(X: Array) -> Array: + """Sets the diagonal of a matrix to zero.""" + if X.shape[0] != X.shape[1]: + raise ValueError( + "Diagonal mask can only mask square matrices. Found {}x{}.".format( + X.shape[0], X.shape[1] + ) + ) + if len(X.shape) > 3: + raise ValueError( + "Diagonal mask can only mask rank-2 or rank-3 tensors. Found {}.".format( + len(X.shape) + ) + ) + N = X.shape[0] + # NOTE(schsam): It seems potentially dangerous to set nans to 0 here. + # However, masking nans also doesn't seem to work. So it also seems + # necessary. At the very least we should do some error checking. + X = jnp.nan_to_num(X) + mask = f32(1.0) - jnp.eye(N, dtype=X.dtype) + if len(X.shape) == 3: + mask = jnp.reshape(mask, (N, N, 1)) + return mask * X + + +def _check_species_dtype(species): + if species.dtype == i32 or species.dtype == i64: + return + msg = "Species has wrong dtype. Expected integer but found {}.".format(species.dtype) + raise ValueError(msg) + + +def _split_params_and_combinators(kwargs): + combinators = {} + params = {} + + for k, v in kwargs.items(): + if isinstance(v, Callable): + combinators[k] = v + elif isinstance(v, tuple) and isinstance(v[0], Callable): + assert len(v) == 2 + combinators[k] = v[0] + params[k] = v[1] + else: + params[k] = v + return params, combinators + + +def pair( + fn: Callable[..., Array], + displacement_or_metric: DisplacementOrMetricFn, + species: Optional[Array] = None, + reduce_axis: Optional[Tuple[int, ...]] = None, + keepdims: bool = False, + ignore_unused_parameters: bool = False, + **kwargs, +) -> Callable[..., Array]: + """Promotes a function that acts on a pair of particles to one on a system. + + Args: + fn: A function that takes an ndarray of pairwise distances or displacements + of shape `[n, m]` or `[n, m, d_in]` respectively as well as kwargs + specifying parameters for the function. fn returns an ndarray of + evaluations of shape `[n, m, d_out]`. + metric: A function that takes two ndarray of positions of shape + `[spatial_dimension]` and `[spatial_dimension]` respectively and returns + an ndarray of distances or displacements of shape `[]` or `[d_in]` + respectively. The metric can optionally take a floating point time as a + third argument. + species: A list of species for the different particles. This should either + be None (in which case it is assumed that all the particles have the same + species), an integer ndarray of shape `[n]` with species data, or an + integer in which case the species data will be specified dynamically with + `species` giving the maximum number of types of particles. Note: that + dynamic species specification is less efficient, because we cannot + specialize shape information. + reduce_axis: A list of axes to reduce over. This is supplied to `jnp.sum` + and so the same convention is used. + keepdims: A boolean specifying whether the empty dimensions should be kept + upon reduction. This is supplied to `jnp.sum` and so the same convention + is used. + ignore_unused_parameters: A boolean that denotes whether dynamically + specified keyword arguments passed to the mapped function get ignored + if they were not first specified as keyword arguments when calling + `smap.pair(...)`. + kwargs: Arguments providing parameters to the mapped function. In cases + where no species information is provided these should be either + + 1) a scalar + 2) an ndarray of shape `[n]` + 3) an ndarray of shape `[n, n]`, + 4) a ParameterTree containing a PyTree of parameters and a mapping. See + ParameterTree for details. + 5) a binary function that determines how per-particle parameters are to + be combined + 6) a binary function as well as a default set of parameters as in 2) + or 4). + + If unspecified then this is taken to be the average of the + two per-particle parameters. If species information is provided then the + parameters should be specified as either + + 1) a scalar + 2) an ndarray of shape `[max_species, max_species]` + 3) a ParameterTree containing a PyTree of parameters and a mapping. See + ParameterTree for details. + + Returns: + A function fn_mapped. + + If species is `None` or statically specified then `fn_mapped` takes as + arguments an ndarray of positions of shape `[n, spatial_dimension]`. + + If species is dynamic then `fn_mapped` takes as input an ndarray of shape + `[n, spatial_dimension]`, an integer ndarray of species of shape `[n]`, and + an integer specifying the maximum species. + + The mapped function can also optionally take keyword arguments that get + threaded through the metric. + """ + + kwargs, param_combinators = _split_params_and_combinators(kwargs) + + merge_dicts = partial( + util.merge_dicts, ignore_unused_parameters=ignore_unused_parameters + ) + + if species is None: + + def fn_mapped(R: Array, **dynamic_kwargs) -> Array: + d = space.map_product(partial(displacement_or_metric, **dynamic_kwargs)) + _kwargs = merge_dicts(kwargs, dynamic_kwargs) + _kwargs = _kwargs_to_parameters(None, _kwargs, param_combinators) + dr = d(R, R) + # NOTE(schsam): Currently we place a diagonal mask no matter what function + # we are mapping. Should this be an option? + return high_precision_sum( + _diagonal_mask(fn(dr, **_kwargs)), axis=reduce_axis, keepdims=keepdims + ) * f32(0.5) + + elif util.is_array(species): + species = onp.array(species) + _check_species_dtype(species) + species_count = int(onp.max(species)) + if reduce_axis is not None or keepdims: + # TODO(schsam): Support reduce_axis with static species. + raise ValueError + + def fn_mapped(R, **dynamic_kwargs): + U = f32(0.0) + d = space.map_product(partial(displacement_or_metric, **dynamic_kwargs)) + for i in range(species_count + 1): + for j in range(i, species_count + 1): + _kwargs = merge_dicts(kwargs, dynamic_kwargs) + s_kwargs = _kwargs_to_parameters((i, j), _kwargs, param_combinators) + Ra = R[species == i] + Rb = R[species == j] + dr = d(Ra, Rb) + if j == i: + dU = high_precision_sum(_diagonal_mask(fn(dr, **s_kwargs))) + U = U + f32(0.5) * dU + else: + dU = high_precision_sum(fn(dr, **s_kwargs)) + U = U + dU + return U + + elif isinstance(species, int): + species_count = species + + def fn_mapped(R, species, **dynamic_kwargs): + _check_species_dtype(species) + U = f32(0.0) + N = R.shape[0] + d = space.map_product(partial(displacement_or_metric, **dynamic_kwargs)) + _kwargs = merge_dicts(kwargs, dynamic_kwargs) + dr = d(R, R) + for i in range(species_count): + for j in range(species_count): + s_kwargs = _kwargs_to_parameters((i, j), _kwargs, param_combinators) + mask_a = jnp.array(jnp.reshape(species == i, (N,)), dtype=R.dtype) + mask_b = jnp.array(jnp.reshape(species == j, (N,)), dtype=R.dtype) + mask = mask_a[:, jnp.newaxis] * mask_b[jnp.newaxis, :] + if i == j: + mask = mask * _diagonal_mask(mask) + dU = mask * fn(dr, **s_kwargs) + U = U + high_precision_sum(dU, axis=reduce_axis, keepdims=keepdims) + return U / f32(2.0) + + else: + raise ValueError( + "Species must be None, an ndarray, or an integer. Found {}.".format(species) + ) + return fn_mapped + + +# Mapping pairwise functional forms to systems using neighbor lists. + + +def _get_neighborhood_matrix_params( + format: partition.NeighborListFormat, + idx: Array, + params: Parameter, + combinator: Callable[[Array, Array], Array], +) -> Parameter: + if util.is_array(params): + if params.ndim == 1: + if partition.is_sparse(format): + return space.map_bond(combinator)(params[idx[0]], params[idx[1]]) + else: + return combinator(params[:, None], params[idx]) + return space.map_neighbor(combinator)(params, params[idx]) + elif params.ndim == 2: + + def query(id_a, id_b): + return params[id_a, id_b] + + if partition.is_sparse(format): + return space.map_bond(query)(idx[0], idx[1]) + else: + query = vmap(vmap(query, (None, 0))) + return query(jnp.arange(idx.shape[0], dtype=jnp.int32), idx) + elif params.ndim == 0: + return params + else: + raise ValueError( + "Parameter array must be either a scalar, a vector, " + f"or a matrix. Found ndim={params.ndim}." + ) + elif isinstance(params, ParameterTree): + if params.mapping is ParameterTreeMapping.Global: + return params.tree + elif params.mapping is ParameterTreeMapping.PerParticle: + if partition.is_sparse(format): + c_fn = space.map_bond(combinator) + return tree_map(lambda p: c_fn(p[idx[0]], p[idx[1]]), params.tree) + else: + c_fn = space.map_neighbor(combinator) + return tree_map(lambda p: c_fn(p, p[idx]), params.tree) + elif params.mapping is ParameterTreeMapping.PerBond: + + def query(p, id_a, id_b): + return p[id_a, id_b] + + if partition.is_sparse(format): + c_fn = lambda p: space.map_bond(partial(query, p))(idx[0], idx[1]) + return tree_map(c_fn, params.tree) + else: + r = jnp.arange(idx.shape[0], dtype=jnp.int32) + c_fn = lambda p: vmap(vmap(partial(query, p), (None, 0)))(r, idx) + return tree_map(c_fn, params.tree) + else: + raise ValueError( + "Without species information ParameterTreeMapping " + f"be Global or PerParticle. Found {params.mapping}." + ) + elif ( + isinstance(params, int) + or isinstance(params, float) + or jnp.issubdtype(params, jnp.integer) + or jnp.issubdtype(params, jnp.floating) + ): + return params + else: + raise ValueError( + "Parameter must be an array, a ParameterTree, or a " + f"float. Found {type(params)}." + ) + + +def _get_neighborhood_species_params( + format: partition.NeighborListFormat, idx: Array, species: Array, params: Parameter +) -> Parameter: + """Get parameters for interactions between species pairs.""" + + # TODO(schsam): We should do better error checking here. + def lookup(p, species_a, species_b): + return p[species_a, species_b] + + if util.is_array(params): + lookup = partial(lookup, params) + if len(params.shape) == 2: + if partition.is_sparse(format): + return space.map_bond(lookup)(species[idx[0]], species[idx[1]]) + else: + lookup = vmap(vmap(lookup, (None, 0))) + return lookup(species, species[idx]) + elif len(params.shape) == 0: + return params + else: + raise ValueError( + "Params must be a scalar or a 2d array if using a species lookup." + ) + elif isinstance(params, ParameterTree): + if params.mapping is ParameterTreeMapping.Global: + return params.tree + elif params.mapping is ParameterTreeMapping.PerSpecies: + if partition.is_sparse(format): + l_fn = lambda p: space.map_bond(partial(lookup, p))( + species[idx[0]], species[idx[1]] + ) + return tree_map(l_fn, params.tree) + else: + l_fn = lambda p: vmap(vmap(partial(lookup, p), (None, 0)))( + species, species[idx] + ) + return tree_map(l_fn, params.tree) + else: + raise ValueError( + "Parameter tree mapping must be either Global or " + "PerSpecies if using a species lookup." + ) + return params + + +def _neighborhood_kwargs_to_params( + format: partition.NeighborListFormat, + idx: Array, + species: Array, + kwargs: Dict[str, Array], + combinators: Dict[str, Callable], +) -> Dict[str, Array]: + out_dict = {} + for k in kwargs: + if species is None or (util.is_array(kwargs[k]) and kwargs[k].ndim == 1): + combinator = combinators.get(k, lambda x, y: 0.5 * (x + y)) + out_dict[k] = _get_neighborhood_matrix_params( + format, idx, kwargs[k], combinator + ) + else: + if k in combinators: + raise ValueError() + out_dict[k] = _get_neighborhood_species_params( + format, idx, species, kwargs[k] + ) + return out_dict + + +def _vectorized_cond(pred: Array, fn: Callable[[Array], Array], operand: Array) -> Array: + masked = jnp.where(pred, operand, 1) + return jnp.where(pred, fn(masked), 0) + + +def pair_neighbor_list( + fn: Callable[..., Array], + displacement_or_metric: DisplacementOrMetricFn, + species: Optional[Array] = None, + reduce_axis: Optional[Tuple[int, ...]] = None, + ignore_unused_parameters: bool = False, + **kwargs, +) -> Callable[..., Array]: + """Promotes a function acting on pairs of particles to use neighbor lists. + + Args: + fn: A function that takes an ndarray of pairwise distances or displacements + of shape `[n, m]` or `[n, m, d_in]` respectively as well as kwargs + specifying parameters for the function. fn returns an ndarray of + evaluations of shape `[n, m, d_out]`. + metric: A function that takes two ndarray of positions of shape + `[spatial_dimension]` and `[spatial_dimension]` respectively and returns + an ndarray of distances or displacements of shape `[]` or `[d_in]` + respectively. The metric can optionally take a floating point time as a + third argument. + species: Species information for the different particles. Should either + be None (in which case it is assumed that all the particles have the same + species), an integer array of shape `[n]` with species data. Note that + species data can be specified dynamically by passing a `species` keyword + argument to the mapped function. + reduce_axis: A list of axes to reduce over. We use a convention where axis + 0 corresponds to the particles, axis 1 corresponds to neighbors, and the + remaining axes correspond to the output axes of `fn`. Note that it is not + well-defined to sum over particles without summing over neighbors. One + also cannot report per-particle values (excluding axis `0`) for neighbor + lists whose format is `OrderedSparse`. + ignore_unused_parameters: A boolean that denotes whether dynamically + specified keyword arguments passed to the mapped function get ignored + if they were not first specified as keyword arguments when calling + `smap.pair_neighbor_list(...)`. + kwargs: Arguments providing parameters to the mapped function. In cases + where no species information is provided these should be either + + 1) a scalar + 2) an ndarray of shape `[n]` + 3) an ndarray of shape `[n, n]`, + 4) a ParameterTree containing a PyTree of parameters and a mapping. See + ParameterTree for details. + 5) a binary function that determines how per-particle parameters are + to be combined + + If unspecified then this is taken to be the average of the + two per-particle parameters. If species information is provided then the + parameters should be specified as either + + 1) a scalar + 2) an ndarray of shape `[max_species, max_species]` + 3) a ParameterTree containing a PyTree of parameters and a mapping. See + ParameterTree for details. + + Returns: + A function `fn_mapped` that takes an ndarray of floats of shape `[N, d_in]` + of positions and and ndarray of integers of shape `[N, max_neighbors]` + specifying neighbors. + """ + kwargs, param_combinators = _split_params_and_combinators(kwargs) + merge_dicts = partial( + util.merge_dicts, ignore_unused_parameters=ignore_unused_parameters + ) + + def fn_mapped(R: Array, neighbor: partition.NeighborList, **dynamic_kwargs) -> Array: + d = partial(displacement_or_metric, **dynamic_kwargs) + _species = dynamic_kwargs.get("species", species) + + normalization = 2.0 + + if partition.is_sparse(neighbor.format): + d = space.map_bond(d) + dR = d(R[neighbor.idx[0]], R[neighbor.idx[1]]) + mask = neighbor.idx[0] < R.shape[0] + if neighbor.format is partition.OrderedSparse: + normalization = 1.0 + else: + d = space.map_neighbor(d) + R_neigh = R[neighbor.idx] + dR = d(R, R_neigh) + mask = neighbor.idx < R.shape[0] + + merged_kwargs = merge_dicts(kwargs, dynamic_kwargs) + merged_kwargs = _neighborhood_kwargs_to_params( + neighbor.format, neighbor.idx, _species, merged_kwargs, param_combinators + ) + out = fn(dR, **merged_kwargs) + if out.ndim > mask.ndim: + ddim = out.ndim - mask.ndim + mask = jnp.reshape(mask, mask.shape + (1,) * ddim) + out *= mask + + if reduce_axis is None: + return util.high_precision_sum(out) / normalization + + if 0 in reduce_axis and 1 not in reduce_axis: + raise ValueError() + + if not partition.is_sparse(neighbor.format): + return util.high_precision_sum(out, reduce_axis) / normalization + + _reduce_axis = tuple(a - 1 for a in reduce_axis if a > 1) + + if 0 in reduce_axis: + return util.high_precision_sum(out, (0,) + _reduce_axis) + + if neighbor.format is partition.OrderedSparse: + raise ValueError( + "Cannot report per-particle values with a neighbor " + "list whose format is `OrderedSparse`. Please use " + "either `Dense` or `Sparse`." + ) + + out = util.high_precision_sum(out, _reduce_axis) + return ops.segment_sum(out, neighbor.idx[0], R.shape[0]) / normalization + + return fn_mapped + + +def triplet( + fn: Callable[..., Array], + displacement_or_metric: DisplacementOrMetricFn, + species: Optional[Array] = None, + reduce_axis: Optional[Tuple[int, ...]] = None, + keepdims: bool = False, + ignore_unused_parameters: bool = False, + **kwargs, +) -> Callable[..., Array]: + """Promotes a function that acts on triples of particles to one on a system. + + Many empirical potentials in jax_md include three-body angular terms (e.g. + Stillinger Weber). This utility function simplifies the loss computation + in such cases by converting a function that takes in two pairwise + displacements or distances to one that only requires the system as input. + + Args: + fn: A function that takes an ndarray of two distances or displacements + from a central atom, both of shape `[n, m]` or `[n, m, d_in]` + respectively, as well as kwargs specifying parameters for the function. + metric: A function that takes two ndarray of positions of shape + `[spatial_dimensions]` and `[spatial_dimensions]` respectively and + returns an ndarray of distances or displacements of shape `[]` or + `[d_in]` respectively. + species: A list of species for the different particles. This should either + be None (in which case it is assumed that all the particles have the same + species), an integer ndarray of shape `[n]` with species data, or an + integer in which case the species data will be specified dynamically with + `species` giving the maximum number of types of particles. Note: that + dynamic species specification is less efficient, because we cannot + specialize shape information. + reduce_axis: A list of axis to reduce over. This is supplied to np.sum and + the same convention is used. + keepdims: A boolean specifying whether the empty dimensions should be kept + upon reduction. This is supplied to np.sum and so the same convention + is used. + ignore_unused_parameters: A boolean that denotes whether dynamically + specified keyword arguments passed to the mapped function get ignored + if they were not first specified as keyword arguments when calling + `smap.triplet(...)`. + kwargs: Argument providing parameters to the mapped function. In cases + where no species information is provided, these should either be + + 1) a scalar + 2) an ndarray of shape `[n]` based on the central atom + 3) an ndarray of shape `[n, n, n]` defining triplet interactions. + + If species information is provided, then the parameters should + be specified as either + + 1) a scalar + 2) an ndarray of shape `[max_species]` + 3) an ndarray of shape `[max_species, max_species, max_species]` + defining triplet interactions. + + Returns: + A function `fn_mapped`. + + If species is None or statically specified, then `fn_mapped` takes as + arguments an ndarray of positions of shape `[n, spatial_dimension]`. + + If species is dynamic then `fn_mapped` takes as input an ndarray of shape + `[n, spatial_dimension]`, an integer ndarray of species of shape `[n]`, and + an integer specifying the maximum species. + + The mapped function can also optionally take keyword arguments that get + threaded through the metric. + """ + + merge_dicts = partial( + util.merge_dicts, ignore_unused_parameters=ignore_unused_parameters + ) + + def extract_parameters_by_dim(kwargs, dim: Union[int, List[int]] = 0): + """Extract parameters from a dictionary via dimension.""" + if isinstance(dim, int): + dim = [dim] + return {name: value for name, value in kwargs.items() if value.ndim in dim} + + if species is None: + + def fn_mapped(R, **dynamic_kwargs) -> Array: + d = space.map_product(partial(displacement_or_metric, **dynamic_kwargs)) + _kwargs = merge_dicts(kwargs, dynamic_kwargs) + _kwargs = _kwargs_to_parameters(species, _kwargs, {}) + dR = d(R, R) + compute_triplet = partial(fn, **_kwargs) + output = vmap(vmap(vmap(compute_triplet, (None, 0)), (0, None)), 0)(dR, dR) + return high_precision_sum(output, axis=reduce_axis, keepdims=keepdims) / 2.0 + + elif util.is_array(species): + + def fn_mapped(R, **dynamic_kwargs): + d = partial(displacement_or_metric, **dynamic_kwargs) + idx = onp.tile(onp.arange(R.shape[0]), [R.shape[0], 1]) + dR = vmap(vmap(d, (None, 0)))(R, R[idx]) + + _kwargs = merge_dicts(kwargs, dynamic_kwargs) + + mapped_args = extract_parameters_by_dim(_kwargs, [3]) + mapped_args = { + arg_name: arg_value[species] + for arg_name, arg_value in mapped_args.items() + } + # While we support 2 dimensional inputs, these often make less sense + # as the parameters do not depend on the central atom + unmapped_args = extract_parameters_by_dim(_kwargs, [0]) + + if extract_parameters_by_dim(_kwargs, [1, 2]): + assert ValueError( + "Improper argument dimensions (1 or 2) not well defined for triplets." + ) + + def compute_triplet(dR, mapped_args, unmapped_args): + paired_args = extract_parameters_by_dim(mapped_args, 2) + paired_args.update(extract_parameters_by_dim(unmapped_args, 2)) + + unpaired_args = extract_parameters_by_dim(mapped_args, 0) + unpaired_args.update(extract_parameters_by_dim(unmapped_args, 0)) + + output_fn = lambda dR1, dR2, paired_args: fn( + dR1, dR2, **unpaired_args, **paired_args + ) + neighbor_args = _neighborhood_kwargs_to_params( + partition.Dense, idx, species, paired_args, {} + ) + output_fn = vmap(vmap(output_fn, (None, 0, 0)), (0, None, 0)) + return output_fn(dR, dR, neighbor_args) + + output_fn = partial(compute_triplet, unmapped_args=unmapped_args) + output = vmap(output_fn)(dR, mapped_args) + return high_precision_sum(output, axis=reduce_axis, keepdims=keepdims) / 2.0 + + elif isinstance(species, int): + raise NotImplementedError + else: + raise ValueError( + "Species must be None, an ndarray, or Dynamic. Found {}.".format(species) + ) + return fn_mapped diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py index 7882d6fb..4a8b2f21 100644 --- a/apax/utils/jax_md_reduced/space.py +++ b/apax/utils/jax_md_reduced/space.py @@ -14,7 +14,7 @@ from typing import Callable, Union, Tuple, Any, Optional -from jax import custom_jvp +from jax import custom_jvp, vmap import jax.numpy as jnp @@ -23,6 +23,7 @@ from apax.utils.jax_md_reduced.util import f64 from apax.utils.jax_md_reduced.util import safe_mask +from jax_md import space # Types @@ -40,280 +41,294 @@ def inverse(box: Box) -> Box: - """Compute the inverse of an affine transformation.""" - if jnp.isscalar(box) or box.size == 1: - return 1 / box - elif box.ndim == 1: - return 1 / box - elif box.ndim == 2: - return jnp.linalg.inv(box) - raise ValueError(('Box must be either: a scalar, a vector, or a matrix. ' - f'Found {box}.')) + """Compute the inverse of an affine transformation.""" + if jnp.isscalar(box) or box.size == 1: + return 1 / box + elif box.ndim == 1: + return 1 / box + elif box.ndim == 2: + return jnp.linalg.inv(box) + raise ValueError(f"Box must be either: a scalar, a vector, or a matrix. Found {box}.") def _get_free_indices(n: int) -> str: - return ''.join([chr(ord('a') + i) for i in range(n)]) + return "".join([chr(ord("a") + i) for i in range(n)]) + def raw_transform(box: Box, R: Array) -> Array: - """Apply an affine transformation to positions. - - See `periodic_general` for a description of the semantics of `box`. - - Args: - box: An affine transformation described in `periodic_general`. - R: Array of positions. Should have shape `(..., spatial_dimension)`. - - Returns: - A transformed array positions of shape `(..., spatial_dimension)`. - """ - if jnp.isscalar(box) or box.size == 1: - return R * box - elif box.ndim == 1: - indices = _get_free_indices(R.ndim - 1) + 'i' - return jnp.einsum(f'i,{indices}->{indices}', box, R) - elif box.ndim == 2: - free_indices = _get_free_indices(R.ndim - 1) - left_indices = free_indices + 'j' - right_indices = free_indices + 'i' - return jnp.einsum(f'ij,{left_indices}->{right_indices}', box, R) - raise ValueError(('Box must be either: a scalar, a vector, or a matrix. ' - f'Found {box}.')) + """Apply an affine transformation to positions. + + See `periodic_general` for a description of the semantics of `box`. + + Args: + box: An affine transformation described in `periodic_general`. + R: Array of positions. Should have shape `(..., spatial_dimension)`. + + Returns: + A transformed array positions of shape `(..., spatial_dimension)`. + """ + if jnp.isscalar(box) or box.size == 1: + return R * box + elif box.ndim == 1: + indices = _get_free_indices(R.ndim - 1) + "i" + return jnp.einsum(f"i,{indices}->{indices}", box, R) + elif box.ndim == 2: + free_indices = _get_free_indices(R.ndim - 1) + left_indices = free_indices + "j" + right_indices = free_indices + "i" + return jnp.einsum(f"ij,{left_indices}->{right_indices}", box, R) + raise ValueError(f"Box must be either: a scalar, a vector, or a matrix. Found {box}.") + @custom_jvp def transform(box: Box, R: Array) -> Array: - """Apply an affine transformation to positions. + """Apply an affine transformation to positions. - See `periodic_general` for a description of the semantics of `box`. + See `periodic_general` for a description of the semantics of `box`. - Args: - box: An affine transformation described in `periodic_general`. - R: Array of positions. Should have shape `(..., spatial_dimension)`. + Args: + box: An affine transformation described in `periodic_general`. + R: Array of positions. Should have shape `(..., spatial_dimension)`. - Returns: - A transformed array positions of shape `(..., spatial_dimension)`. - """ - return raw_transform(box, R) + Returns: + A transformed array positions of shape `(..., spatial_dimension)`. + """ + return raw_transform(box, R) @transform.defjvp def transform_jvp(primals, tangents): - box, R = primals - dbox, dR = tangents - return (transform(box, R), dR + transform(dbox, R)) + box, R = primals + dbox, dR = tangents + return (transform(box, R), dR + transform(dbox, R)) + def pairwise_displacement(Ra: Array, Rb: Array) -> Array: - """Compute a matrix of pairwise displacements given two sets of positions. + """Compute a matrix of pairwise displacements given two sets of positions. - Args: - Ra: Vector of positions; `ndarray(shape=[spatial_dim])`. - Rb: Vector of positions; `ndarray(shape=[spatial_dim])`. + Args: + Ra: Vector of positions; `ndarray(shape=[spatial_dim])`. + Rb: Vector of positions; `ndarray(shape=[spatial_dim])`. - Returns: - Matrix of displacements; `ndarray(shape=[spatial_dim])`. - """ - if len(Ra.shape) != 1: - msg = ( - 'Can only compute displacements between vectors. To compute ' - 'displacements between sets of vectors use vmap or TODO.' - ) - raise ValueError(msg) + Returns: + Matrix of displacements; `ndarray(shape=[spatial_dim])`. + """ + if len(Ra.shape) != 1: + msg = ( + "Can only compute displacements between vectors. To compute " + "displacements between sets of vectors use vmap or TODO." + ) + raise ValueError(msg) - if Ra.shape != Rb.shape: - msg = 'Can only compute displacement between vectors of equal dimension.' - raise ValueError(msg) + if Ra.shape != Rb.shape: + msg = "Can only compute displacement between vectors of equal dimension." + raise ValueError(msg) + + return Ra - Rb - return Ra - Rb def periodic_shift(side: Box, R: Array, dR: Array) -> Array: - """Shifts positions, wrapping them back within a periodic hypercube.""" - return jnp.mod(R + dR, side) + """Shifts positions, wrapping them back within a periodic hypercube.""" + return jnp.mod(R + dR, side) + def free() -> Space: - """Free boundary conditions.""" - def displacement_fn(Ra: Array, Rb: Array, perturbation: Optional[Array]=None, - **unused_kwargs) -> Array: - dR = pairwise_displacement(Ra, Rb) - if perturbation is not None: - dR = raw_transform(perturbation, dR) - return dR - def shift_fn(R: Array, dR: Array, **unused_kwargs) -> Array: - return R + dR - return displacement_fn, shift_fn + """Free boundary conditions.""" + + def displacement_fn( + Ra: Array, Rb: Array, perturbation: Optional[Array] = None, **unused_kwargs + ) -> Array: + dR = pairwise_displacement(Ra, Rb) + if perturbation is not None: + dR = raw_transform(perturbation, dR) + return dR + + def shift_fn(R: Array, dR: Array, **unused_kwargs) -> Array: + return R + dR + + return displacement_fn, shift_fn def periodic_displacement(side: Box, dR: Array) -> Array: - """Wraps displacement vectors into a hypercube. - - Args: - side: Specification of hypercube size. Either, - (a) float if all sides have equal length. - (b) ndarray(spatial_dim) if sides have different lengths. - dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. - Returns: - Matrix of wrapped displacements; `ndarray(shape=[..., spatial_dim])`. - """ - return jnp.mod(dR + side * f32(0.5), side) - f32(0.5) * side + """Wraps displacement vectors into a hypercube. + + Args: + side: Specification of hypercube size. Either, + (a) float if all sides have equal length. + (b) ndarray(spatial_dim) if sides have different lengths. + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of wrapped displacements; `ndarray(shape=[..., spatial_dim])`. + """ + return jnp.mod(dR + side * f32(0.5), side) - f32(0.5) * side + def square_distance(dR: Array) -> Array: - """Computes square distances. - - Args: - dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. - Returns: - Matrix of squared distances; `ndarray(shape=[...])`. - """ - return jnp.sum(dR ** 2, axis=-1) - - -def periodic_general(box: Box, - fractional_coordinates: bool=True, - wrapped: bool=True) -> Space: - """Periodic boundary conditions on a parallelepiped. - - This function defines a simulation on a parallelepiped, :math:`X`, formed by - applying an affine transformation, :math:`T`, to the unit hypercube - :math:`U = [0, 1]^d` along with periodic boundary conditions across all - of the faces. - - Formally, the space is defined such that :math:`X = {Tu : u \in [0, 1]^d}`. - - The affine transformation, :math:`T`, can be specified in a number of different - ways. For a parallelepiped that is: 1) a cube of side length :math:`L`, the affine - transformation can simply be a scalar; 2) an orthorhombic unit cell can be - specified by a vector `[Lx, Ly, Lz]` of lengths for each axis; 3) a general - triclinic cell can be specified by an upper triangular matrix. - - There are a number of ways to parameterize a simulation on :math:`X`. - `periodic_general` supports two parametrizations of :math:`X` that can be selected - using the `fractional_coordinates` keyword argument. - - 1) When `fractional_coordinates=True`, particle positions are stored in the - unit cube, :math:`u\in U`. Here, the displacement function computes the - displacement between :math:`x, y \in X` as :math:`d_X(x, y) = Td_U(u, v)` where - :math:`d_U` is the displacement function on the unit cube, :math:`U`, :math:`x = Tu`, and - :math:`v = Tv` with :math:`u, v \in U`. The derivative of the displacement function - is defined so that derivatives live in :math:`X` (as opposed to being - backpropagated to :math:`U`). The shift function, `shift_fn(R, dR)` is defined - so that :math:`R` is expected to lie in :math:`U` while :math:`dR` should lie in :math:`X`. This - combination enables code such as `shift_fn(R, force_fn(R))` to work as - intended. - - 2) When `fractional_coordinates=False`, particle positions are stored in - the parallelepiped :math:`X`. Here, for :math:`x, y \in X`, the displacement function - is defined as :math:`d_X(x, y) = Td_U(T^{-1}x, T^{-1}y)`. Since there is an - extra multiplication by :math:`T^{-1}`, this parameterization is typically - slower than `fractional_coordinates=False`. As in 1), the displacement - function is defined to compute derivatives in :math:`X`. The shift function - is defined so that :math:`R` and :math:`dR` should both lie in :math:`X`. - - Example: - - .. code-block:: python - - from jax import random - side_length = 10.0 - disp_frac, shift_frac = periodic_general(side_length, - fractional_coordinates=True) - disp_real, shift_real = periodic_general(side_length, - fractional_coordinates=False) - - # Instantiate random positions in both parameterizations. - R_frac = random.uniform(random.PRNGKey(0), (4, 3)) - R_real = side_length * R_frac - - # Make some shift vectors. - dR = random.normal(random.PRNGKey(0), (4, 3)) - - disp_real(R_real[0], R_real[1]) == disp_frac(R_frac[0], R_frac[1]) - transform(side_length, shift_frac(R_frac, 1.0)) == shift_real(R_real, 1.0) - - It is often desirable to deform a simulation cell either: using a finite - deformation during a simulation, or using an infinitesimal deformation while - computing elastic constants. To do this using fractional coordinates, we can - supply a new affine transformation as `displacement_fn(Ra, Rb, box=new_box)`. - When using real coordinates, we can specify positions in a space :math:`X` defined - by an affine transformation :math:`T` and compute displacements in a deformed space - :math:`X'` defined by an affine transformation :math:`T'`. This is done by writing - `displacement_fn(Ra, Rb, new_box=new_box)`. - - There are a few caveats when using `periodic_general`. `periodic_general` - uses the minimum image convention, and so it will fail for potentials whose - cutoff is longer than the half of the side-length of the box. It will also - fail to find the correct image when the box is too deformed. We hope to add a - more robust box for small simulations soon (TODO) along with better error - checking. In the meantime caution is recommended. - - Args: - box: A `(spatial_dim, spatial_dim)` affine transformation. - fractional_coordinates: A boolean specifying whether positions are stored - in the parallelepiped or the unit cube. - wrapped: A boolean specifying whether or not particle positions are - remapped back into the box after each step - Returns: - `(displacement_fn, shift_fn)` tuple. - """ - inv_box = inverse(box) - - def displacement_fn(Ra, Rb, perturbation=None, **kwargs): - _box, _inv_box = box, inv_box - - if 'box' in kwargs: - _box = kwargs['box'] - - if not fractional_coordinates: - _inv_box = inverse(_box) - - if 'new_box' in kwargs: - _box = kwargs['new_box'] - - if not fractional_coordinates: - Ra = transform(_inv_box, Ra) - Rb = transform(_inv_box, Rb) - - dR = periodic_displacement(f32(1.0), pairwise_displacement(Ra, Rb)) - dR = transform(_box, dR) - - if perturbation is not None: - dR = raw_transform(perturbation, dR) - - return dR - - def u(R, dR): - if wrapped: - return periodic_shift(f32(1.0), R, dR) - return R + dR - - def shift_fn(R, dR, **kwargs): - if not fractional_coordinates and not wrapped: - return R + dR - - _box, _inv_box = box, inv_box - if 'box' in kwargs: - _box = kwargs['box'] - _inv_box = inverse(_box) - - if 'new_box' in kwargs: - _box = kwargs['new_box'] - - dR = transform(_inv_box, dR) - if not fractional_coordinates: - R = transform(_inv_box, R) - - R = u(R, dR) - - if not fractional_coordinates: - R = transform(_box, R) - return R + """Computes square distances. + + Args: + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of squared distances; `ndarray(shape=[...])`. + """ + return jnp.sum(dR**2, axis=-1) + + +def periodic_general( + box: Box, fractional_coordinates: bool = True, wrapped: bool = True +) -> Space: + """Periodic boundary conditions on a parallelepiped. + + This function defines a simulation on a parallelepiped, :math:`X`, formed by + applying an affine transformation, :math:`T`, to the unit hypercube + :math:`U = [0, 1]^d` along with periodic boundary conditions across all + of the faces. + + Formally, the space is defined such that :math:`X = {Tu : u \in [0, 1]^d}`. + + The affine transformation, :math:`T`, can be specified in a number of different + ways. For a parallelepiped that is: 1) a cube of side length :math:`L`, the affine + transformation can simply be a scalar; 2) an orthorhombic unit cell can be + specified by a vector `[Lx, Ly, Lz]` of lengths for each axis; 3) a general + triclinic cell can be specified by an upper triangular matrix. + + There are a number of ways to parameterize a simulation on :math:`X`. + `periodic_general` supports two parametrizations of :math:`X` that can be selected + using the `fractional_coordinates` keyword argument. + + 1) When `fractional_coordinates=True`, particle positions are stored in the + unit cube, :math:`u\in U`. Here, the displacement function computes the + displacement between :math:`x, y \in X` as :math:`d_X(x, y) = Td_U(u, v)` where + :math:`d_U` is the displacement function on the unit cube, :math:`U`, :math:`x = Tu`, and + :math:`v = Tv` with :math:`u, v \in U`. The derivative of the displacement function + is defined so that derivatives live in :math:`X` (as opposed to being + backpropagated to :math:`U`). The shift function, `shift_fn(R, dR)` is defined + so that :math:`R` is expected to lie in :math:`U` while :math:`dR` should lie in :math:`X`. This + combination enables code such as `shift_fn(R, force_fn(R))` to work as + intended. + + 2) When `fractional_coordinates=False`, particle positions are stored in + the parallelepiped :math:`X`. Here, for :math:`x, y \in X`, the displacement function + is defined as :math:`d_X(x, y) = Td_U(T^{-1}x, T^{-1}y)`. Since there is an + extra multiplication by :math:`T^{-1}`, this parameterization is typically + slower than `fractional_coordinates=False`. As in 1), the displacement + function is defined to compute derivatives in :math:`X`. The shift function + is defined so that :math:`R` and :math:`dR` should both lie in :math:`X`. + + Example: + + .. code-block:: python + + from jax import random + side_length = 10.0 + disp_frac, shift_frac = periodic_general(side_length, + fractional_coordinates=True) + disp_real, shift_real = periodic_general(side_length, + fractional_coordinates=False) + + # Instantiate random positions in both parameterizations. + R_frac = random.uniform(random.PRNGKey(0), (4, 3)) + R_real = side_length * R_frac + + # Make some shift vectors. + dR = random.normal(random.PRNGKey(0), (4, 3)) + + disp_real(R_real[0], R_real[1]) == disp_frac(R_frac[0], R_frac[1]) + transform(side_length, shift_frac(R_frac, 1.0)) == shift_real(R_real, 1.0) + + It is often desirable to deform a simulation cell either: using a finite + deformation during a simulation, or using an infinitesimal deformation while + computing elastic constants. To do this using fractional coordinates, we can + supply a new affine transformation as `displacement_fn(Ra, Rb, box=new_box)`. + When using real coordinates, we can specify positions in a space :math:`X` defined + by an affine transformation :math:`T` and compute displacements in a deformed space + :math:`X'` defined by an affine transformation :math:`T'`. This is done by writing + `displacement_fn(Ra, Rb, new_box=new_box)`. + + There are a few caveats when using `periodic_general`. `periodic_general` + uses the minimum image convention, and so it will fail for potentials whose + cutoff is longer than the half of the side-length of the box. It will also + fail to find the correct image when the box is too deformed. We hope to add a + more robust box for small simulations soon (TODO) along with better error + checking. In the meantime caution is recommended. + + Args: + box: A `(spatial_dim, spatial_dim)` affine transformation. + fractional_coordinates: A boolean specifying whether positions are stored + in the parallelepiped or the unit cube. + wrapped: A boolean specifying whether or not particle positions are + remapped back into the box after each step + Returns: + `(displacement_fn, shift_fn)` tuple. + """ + inv_box = inverse(box) + + def displacement_fn(Ra, Rb, perturbation=None, **kwargs): + _box, _inv_box = box, inv_box + + if "box" in kwargs: + _box = kwargs["box"] + + if not fractional_coordinates: + _inv_box = inverse(_box) + + if "new_box" in kwargs: + _box = kwargs["new_box"] + + if not fractional_coordinates: + Ra = transform(_inv_box, Ra) + Rb = transform(_inv_box, Rb) + + dR = periodic_displacement(f32(1.0), pairwise_displacement(Ra, Rb)) + dR = transform(_box, dR) + + if perturbation is not None: + dR = raw_transform(perturbation, dR) + + return dR + + def u(R, dR): + if wrapped: + return periodic_shift(f32(1.0), R, dR) + return R + dR + + def shift_fn(R, dR, **kwargs): + if not fractional_coordinates and not wrapped: + return R + dR + + _box, _inv_box = box, inv_box + if "box" in kwargs: + _box = kwargs["box"] + _inv_box = inverse(_box) + + if "new_box" in kwargs: + _box = kwargs["new_box"] + + dR = transform(_inv_box, dR) + if not fractional_coordinates: + R = transform(_inv_box, R) + + R = u(R, dR) + + if not fractional_coordinates: + R = transform(_box, R) + return R + + return displacement_fn, shift_fn - return displacement_fn, shift_fn def distance(dR: Array) -> Array: - """Computes distances. - - Args: - dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. - Returns: - Matrix of distances; `ndarray(shape=[...])`. - """ - dr = square_distance(dR) - return safe_mask(dr > 0, jnp.sqrt, dr) \ No newline at end of file + """Computes distances. + + Args: + dR: Matrix of displacements; `ndarray(shape=[..., spatial_dim])`. + Returns: + Matrix of distances; `ndarray(shape=[...])`. + """ + dr = square_distance(dR) + return safe_mask(dr > 0, jnp.sqrt, dr) + + +def map_bond(metric_or_displacement: DisplacementOrMetricFn) -> DisplacementOrMetricFn: + """Vectorizes a metric or displacement function over bonds.""" + return vmap(metric_or_displacement, (0, 0), 0) diff --git a/apax/utils/jax_md_reduced/util.py b/apax/utils/jax_md_reduced/util.py index abd25d26..c61af9a6 100644 --- a/apax/utils/jax_md_reduced/util.py +++ b/apax/utils/jax_md_reduced/util.py @@ -12,11 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Defines utility functions.""" + +from typing import Iterable, Union, Optional, Any + +from jax.tree_util import register_pytree_node +from jax.lib import xla_bridge import jax.numpy as jnp -from typing import Any from jax import jit + from functools import partial +import numpy as onp + Array = jnp.ndarray PyTree = Any @@ -27,7 +35,70 @@ f32 = jnp.float32 f64 = jnp.float64 + +CUSTOM_SIMULATION_TYPE = [] + + +def register_custom_simulation_type(t: Any): + global CUSTOM_SIMULATION_TYPE + CUSTOM_SIMULATION_TYPE += [t] + + +def check_custom_simulation_type(x: Any) -> bool: + if type(x) in CUSTOM_SIMULATION_TYPE: + raise ValueError() + + +def static_cast(*xs): + """Function to cast a value to the lowest dtype that can express it.""" + # NOTE(schsam): static_cast is so named because it cannot be jit. + if xla_bridge.get_backend().platform == "tpu": + return (jnp.array(x, jnp.float32) for x in xs) + else: + return (jnp.array(x, dtype=onp.min_scalar_type(x)) for x in xs) + + +def register_pytree_namedtuple(cls): + register_pytree_node(cls, lambda xs: (tuple(xs), None), lambda _, xs: cls(*xs)) + + +def merge_dicts(a, b, ignore_unused_parameters=False): + if not ignore_unused_parameters: + return {**a, **b} + + merged = dict(a) + for key in merged.keys(): + b_val = b.get(key) + if b_val is not None: + merged[key] = b_val + return merged + + @partial(jit, static_argnums=(1,)) def safe_mask(mask, fn, operand, placeholder=0): - masked = jnp.where(mask, operand, 0) - return jnp.where(mask, fn(masked), placeholder) \ No newline at end of file + masked = jnp.where(mask, operand, 0) + return jnp.where(mask, fn(masked), placeholder) + + +def high_precision_sum( + X: Array, axis: Optional[Union[Iterable[int], int]] = None, keepdims: bool = False +): + """Sums over axes at 64-bit precision then casts back to original dtype.""" + if jnp.issubdtype(X.dtype, jnp.integer): + dtyp = jnp.int64 + elif jnp.issubdtype(X.dtype, jnp.complexfloating): + dtyp = jnp.complex128 + else: + dtyp = jnp.float64 + + return jnp.array(jnp.sum(X, axis=axis, dtype=dtyp, keepdims=keepdims), dtype=X.dtype) + + +def maybe_downcast(x): + if isinstance(x, jnp.ndarray) and x.dtype is jnp.dtype("float64"): + return x + return jnp.array(x, f32) + + +def is_array(x: Any) -> bool: + return isinstance(x, (jnp.ndarray, onp.ndarray)) From 52fe02da2921a3aa4ed41124efd6dc07c6c9ee7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:13:56 +0100 Subject: [PATCH 038/192] exclude jaxmd from linting --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1753282e..cef0d1dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,3 +26,4 @@ repos: hooks: - id: flake8 additional_dependencies: [ flake8-isort ] + exclude: ^apax/utils/jax_md_reduced/ From e074a1856b7c7fd5e0c522eda9e9e5a1c4dc4415 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:16:27 +0000 Subject: [PATCH 039/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/data/input_pipeline.py | 14 ++++----- apax/train/trainer.py | 10 +++---- apax/utils/jax_md_reduced/partition.py | 12 ++++---- apax/utils/jax_md_reduced/quantity.py | 10 +++---- apax/utils/jax_md_reduced/simulate.py | 41 +++++++++++--------------- tests/integration_tests/md/test_md.py | 4 ++- 6 files changed, 41 insertions(+), 50 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 3e53fa33..6832c587 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -134,14 +134,12 @@ def dataset_from_dicts( for key, val in labels["fixed"].items(): labels["fixed"][key] = tf.constant(val) - ds = tf.data.Dataset.from_tensor_slices( - ( - inputs["ragged"], - inputs["fixed"], - labels["ragged"], - labels["fixed"], - ) - ) + ds = tf.data.Dataset.from_tensor_slices(( + inputs["ragged"], + inputs["fixed"], + labels["ragged"], + labels["fixed"], + )) return ds diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 684203eb..0c96277b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,12 +109,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index b1f48603..a89af1c8 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -265,9 +265,9 @@ class NeighborList: format: NeighborListFormat = dataclasses.static_field() cell_size: Optional[float] = dataclasses.static_field() cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() - update_fn: Callable[ - [Array, "NeighborList"], "NeighborList" - ] = dataclasses.static_field() + update_fn: Callable[[Array, "NeighborList"], "NeighborList"] = ( + dataclasses.static_field() + ) def update(self, position: Array, **kwargs) -> "NeighborList": return self.update_fn(position, self, **kwargs) @@ -340,9 +340,9 @@ class NeighborList: format: NeighborListFormat = dataclasses.static_field() cell_size: Optional[float] = dataclasses.static_field() cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() - update_fn: Callable[ - [Array, "NeighborList"], "NeighborList" - ] = dataclasses.static_field() + update_fn: Callable[[Array, "NeighborList"], "NeighborList"] = ( + dataclasses.static_field() + ) def update(self, position: Array, **kwargs) -> "NeighborList": return self.update_fn(position, self, **kwargs) diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py index 58f200b5..020af029 100644 --- a/apax/utils/jax_md_reduced/quantity.py +++ b/apax/utils/jax_md_reduced/quantity.py @@ -333,12 +333,10 @@ def average_pair_correlation_results(gofr, species=None): if species is None: return jnp.mean(gofr, axis=0) species_types = jnp.unique(species) # note: this returns in sorted order - return jnp.array( - [ - [jnp.mean(gofr[si][species == s], axis=0) for s in species_types] - for si in range(species_types.size) - ] - ) + return jnp.array([ + [jnp.mean(gofr[si][species == s], axis=0) for s in species_types] + for si in range(species_types.size) + ]) def pair_correlation( diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index e3c2ed3e..6e067675 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -14,23 +14,23 @@ """Code to simulate systems in various statistical ensembles. - This file contains a number of different methods that can be used to - simulate systems in a variety of ensembles. - - In general, simulation code follows the same overall structure as optimizers - in JAX. Simulations are tuples of two functions: - - init_fn: - Function that initializes the state of a system. Should take - positions as an ndarray of shape `[n, output_dimension]`. Returns a state - which will be a namedtuple. - apply_fn: - Function that takes a state and produces a new state after one - step of optimization. - - One question that we need to think about is whether the simulations should - also return a function that computes the invariant for that ensemble. This - can be used for testing purposes, but is not often used otherwise. +This file contains a number of different methods that can be used to +simulate systems in a variety of ensembles. + +In general, simulation code follows the same overall structure as optimizers +in JAX. Simulations are tuples of two functions: + + init_fn: + Function that initializes the state of a system. Should take + positions as an ndarray of shape `[n, output_dimension]`. Returns a state + which will be a namedtuple. + apply_fn: + Function that takes a state and produces a new state after one + step of optimization. + +One question that we need to think about is whether the simulations should +also return a function that computes the invariant for that ensemble. This +can be used for testing purposes, but is not often used otherwise. """ from collections import namedtuple @@ -849,12 +849,7 @@ def U(eps): def sinhx_x(x): """Taylor series for sinh(x) / x as x -> 0.""" return ( - 1 - + x**2 / 6 - + x**4 / 120 - + x**6 / 5040 - + x**8 / 362_880 - + x**10 / 39_916_800 + 1 + x**2 / 6 + x**4 / 120 + x**6 / 5040 + x**8 / 362_880 + x**10 / 39_916_800 ) def exp_iL1(box, R, V, V_b, **kwargs): diff --git a/tests/integration_tests/md/test_md.py b/tests/integration_tests/md/test_md.py index e34a2dbf..1bfe9eaf 100644 --- a/tests/integration_tests/md/test_md.py +++ b/tests/integration_tests/md/test_md.py @@ -125,7 +125,9 @@ def test_ase_calc(get_tmp_path): atoms = Atoms(atomic_numbers, positions, cell=box) write(initial_structure_path.as_posix(), atoms) - displacement_fn, _ = jax_md_reduced.space.periodic_general(cell_size, fractional_coordinates=False) + displacement_fn, _ = jax_md_reduced.space.periodic_general( + cell_size, fractional_coordinates=False + ) neighbor_fn = jax_md_reduced.partition.neighbor_list( displacement_or_metric=displacement_fn, From 48773c44d6ea7701ca4364dc8edbf86c69b02e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:18:07 +0100 Subject: [PATCH 040/192] added exclude path to isort and black --- .pre-commit-config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cef0d1dc..52dfbe5b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,12 +14,14 @@ repos: rev: 24.1.1 hooks: - id: black + exclude: ^apax/utils/jax_md_reduced/ - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort args: ["--profile", "black", "--filter-files"] + exclude: ^apax/utils/jax_md_reduced/ - repo: https://github.com/pycqa/flake8 rev: 7.0.0 From 948e8237d3395ed23abbf59dddc918b990a073a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:18:58 +0100 Subject: [PATCH 041/192] linting --- .../descriptor/gaussian_moment_descriptor.py | 2 +- apax/layers/empirical.py | 2 +- apax/md/ase_calc.py | 2 +- apax/model/gmnn.py | 2 +- apax/utils/convert.py | 1 + apax/utils/jax_md_reduced/__init__.py | 4 +-- apax/utils/jax_md_reduced/dataclasses.py | 1 + apax/utils/jax_md_reduced/partition.py | 11 +++---- apax/utils/jax_md_reduced/quantity.py | 19 +++++------- apax/utils/jax_md_reduced/simulate.py | 29 +++++++++---------- apax/utils/jax_md_reduced/smap.py | 19 ++++-------- apax/utils/jax_md_reduced/space.py | 13 +++------ apax/utils/jax_md_reduced/util.py | 12 ++++---- 13 files changed, 49 insertions(+), 68 deletions(-) diff --git a/apax/layers/descriptor/gaussian_moment_descriptor.py b/apax/layers/descriptor/gaussian_moment_descriptor.py index a176e367..45dc2862 100644 --- a/apax/layers/descriptor/gaussian_moment_descriptor.py +++ b/apax/layers/descriptor/gaussian_moment_descriptor.py @@ -5,11 +5,11 @@ import jax.numpy as jnp from jax import vmap -from apax.utils import jax_md_reduced from apax.layers.descriptor.basis_functions import RadialFunction from apax.layers.descriptor.moments import geometric_moments from apax.layers.descriptor.triangular_indices import tril_2d_indices, tril_3d_indices from apax.layers.masking import mask_by_neighbor +from apax.utils import jax_md_reduced class GaussianMomentDescriptor(nn.Module): diff --git a/apax/layers/empirical.py b/apax/layers/empirical.py index e3c41669..896c8535 100644 --- a/apax/layers/empirical.py +++ b/apax/layers/empirical.py @@ -6,8 +6,8 @@ import numpy as np from jax import vmap -from apax.utils import jax_md_reduced from apax.layers.masking import mask_by_neighbor +from apax.utils import jax_md_reduced from apax.utils.math import fp64_sum diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 9700d9e4..07bf9d20 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -10,8 +10,8 @@ from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters -from apax.utils.jax_md_reduced import quantity from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import quantity def maybe_vmap(apply, params, Z): diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index 70a7f73c..f0b26d54 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -15,8 +15,8 @@ from apax.layers.properties import stress_times_vol from apax.layers.readout import AtomisticReadout from apax.layers.scaling import PerElementScaleShift +from apax.utils.jax_md_reduced import partition, space from apax.utils.math import fp64_sum -from apax.utils.jax_md_reduced import space, partition DisplacementFn = Callable[[Array, Array], Array] MDModel = Tuple[partition.NeighborFn, Callable, Callable] diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 983b7e4d..d8039862 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -2,6 +2,7 @@ import numpy as np from ase import Atoms from ase.units import Ang, Bohr, Hartree, eV, kcal, kJ, mol + from apax.utils import jax_md_reduced diff --git a/apax/utils/jax_md_reduced/__init__.py b/apax/utils/jax_md_reduced/__init__.py index 3bc9f80a..0059f780 100644 --- a/apax/utils/jax_md_reduced/__init__.py +++ b/apax/utils/jax_md_reduced/__init__.py @@ -1,11 +1,11 @@ from apax.utils.jax_md_reduced import ( + dataclasses, partition, - space, quantity, simulate, smap, + space, util, - dataclasses, ) __all__ = ["partition", "space", "quantity", "simulate", "smap", "util", "dataclasses"] diff --git a/apax/utils/jax_md_reduced/dataclasses.py b/apax/utils/jax_md_reduced/dataclasses.py index df089ed9..5697624a 100644 --- a/apax/utils/jax_md_reduced/dataclasses.py +++ b/apax/utils/jax_md_reduced/dataclasses.py @@ -20,6 +20,7 @@ """ import dataclasses + import jax diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index b1f48603..36a7bafb 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -12,16 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -from functools import partial import logging -from typing import Any, Callable, Optional, Dict, Generator +from enum import Enum, IntEnum +from functools import partial +from typing import Any, Callable, Dict, Generator, Optional import jax.numpy as jnp import numpy as onp +from jax import eval_shape, jit, lax, vmap from jax.core import ShapedArray -from jax import jit, vmap, eval_shape, lax -from enum import IntEnum, Enum -from apax.utils.jax_md_reduced import util, space, dataclasses + +from apax.utils.jax_md_reduced import dataclasses, space, util Array = util.Array PyTree = Any diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py index 58f200b5..b8dc47e7 100644 --- a/apax/utils/jax_md_reduced/quantity.py +++ b/apax/utils/jax_md_reduced/quantity.py @@ -15,22 +15,17 @@ """Describes different physical quantities.""" -from typing import TypeVar, Callable, Union, Tuple, Optional, Any - -from absl import logging +import functools +import operator +from typing import Any, Callable, Optional, Tuple, TypeVar, Union -from jax import grad, vmap, eval_shape -from jax.tree_util import tree_map, tree_reduce import jax.numpy as jnp -from jax import ops -from jax import ShapeDtypeStruct -from jax.tree_util import tree_map, tree_reduce +from absl import logging +from jax import ShapeDtypeStruct, eval_shape, grad, ops, vmap from jax.scipy.special import gammaln +from jax.tree_util import tree_map, tree_reduce -from apax.utils.jax_md_reduced import space, dataclasses, partition, util - -import functools -import operator +from apax.utils.jax_md_reduced import dataclasses, partition, space, util partial = functools.partial diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index e3c2ed3e..43255edb 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -33,25 +33,22 @@ can be used for testing purposes, but is not often used otherwise. """ -from collections import namedtuple - -from typing import Any, Callable, TypeVar, Union, Tuple, Dict, Optional - import functools +from collections import namedtuple +from typing import Any, Callable, Dict, Optional, Tuple, TypeVar, Union -from jax import grad -from jax import jit -from jax import random import jax.numpy as jnp -from jax import lax -from jax.tree_util import tree_map, tree_reduce, tree_flatten, tree_unflatten - -from apax.utils.jax_md_reduced import quantity -from apax.utils.jax_md_reduced import util -from apax.utils.jax_md_reduced import space -from apax.utils.jax_md_reduced import dataclasses -from apax.utils.jax_md_reduced import partition -from apax.utils.jax_md_reduced import smap +from jax import grad, jit, lax, random +from jax.tree_util import tree_flatten, tree_map, tree_reduce, tree_unflatten + +from apax.utils.jax_md_reduced import ( + dataclasses, + partition, + quantity, + smap, + space, + util, +) static_cast = util.static_cast diff --git a/apax/utils/jax_md_reduced/smap.py b/apax/utils/jax_md_reduced/smap.py index 4d30193c..a4096cc5 100644 --- a/apax/utils/jax_md_reduced/smap.py +++ b/apax/utils/jax_md_reduced/smap.py @@ -14,26 +14,19 @@ """Code to transform functions on individual tuples of particles to sets.""" -from functools import reduce, partial - -from typing import Dict, Callable, List, Tuple, Union, Optional - -import math import enum +import math +from functools import partial, reduce from operator import mul +from typing import Callable, Dict, List, Optional, Tuple, Union +import jax.numpy as jnp import numpy as onp - -from jax import lax, ops, vmap, eval_shape, tree_map +from jax import eval_shape, lax, ops, tree_map, vmap from jax.core import ShapedArray from jax.interpreters import partial_eval as pe -import jax.numpy as jnp -from apax.utils.jax_md_reduced import dataclasses -from apax.utils.jax_md_reduced import quantity -from apax.utils.jax_md_reduced import space -from apax.utils.jax_md_reduced import util -from apax.utils.jax_md_reduced import partition +from apax.utils.jax_md_reduced import dataclasses, partition, quantity, space, util high_precision_sum = util.high_precision_sum diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py index 4a8b2f21..7dd072d4 100644 --- a/apax/utils/jax_md_reduced/space.py +++ b/apax/utils/jax_md_reduced/space.py @@ -12,19 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, Union, Tuple, Any, Optional - -from jax import custom_jvp, vmap +from typing import Any, Callable, Optional, Tuple, Union import jax.numpy as jnp - -from apax.utils.jax_md_reduced.util import Array -from apax.utils.jax_md_reduced.util import f32 -from apax.utils.jax_md_reduced.util import f64 -from apax.utils.jax_md_reduced.util import safe_mask - +from jax import custom_jvp, vmap from jax_md import space +from apax.utils.jax_md_reduced.util import Array, f32, f64, safe_mask + # Types diff --git a/apax/utils/jax_md_reduced/util.py b/apax/utils/jax_md_reduced/util.py index c61af9a6..92884ee4 100644 --- a/apax/utils/jax_md_reduced/util.py +++ b/apax/utils/jax_md_reduced/util.py @@ -14,16 +14,14 @@ """Defines utility functions.""" -from typing import Iterable, Union, Optional, Any - -from jax.tree_util import register_pytree_node -from jax.lib import xla_bridge -import jax.numpy as jnp -from jax import jit - from functools import partial +from typing import Any, Iterable, Optional, Union +import jax.numpy as jnp import numpy as onp +from jax import jit +from jax.lib import xla_bridge +from jax.tree_util import register_pytree_node Array = jnp.ndarray PyTree = Any From 0d452e899e8df855ac2a5ac4f7af0c93087cf504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:31:28 +0100 Subject: [PATCH 042/192] poetry update, remove last remaining jaxmd imports --- apax/__init__.py | 4 +- apax/layers/initializers.py | 2 +- apax/layers/properties.py | 2 +- apax/md/io.py | 2 +- apax/md/sim_utils.py | 2 +- apax/model/gmnn.py | 3 +- apax/utils/jax_md_reduced/space.py | 2 +- apax/utils/math.py | 2 +- poetry.lock | 1466 ++++++++--------- pyproject.toml | 1 - .../test_transfer_learning.py | 4 +- 11 files changed, 656 insertions(+), 834 deletions(-) diff --git a/apax/__init__.py b/apax/__init__.py index 7cd23717..c932bb03 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -1,6 +1,6 @@ import os -from jax.config import config as jax_config +import jax os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" -jax_config.update("jax_enable_x64", True) +jax.config.update("jax_enable_x64", True) diff --git a/apax/layers/initializers.py b/apax/layers/initializers.py index aabefb72..db4425eb 100644 --- a/apax/layers/initializers.py +++ b/apax/layers/initializers.py @@ -5,8 +5,8 @@ from jax._src import dtypes from jax.nn.initializers import Initializer -KeyArray = random.KeyArray Array = Any +KeyArray = Array DTypeLikeFloat = Any DTypeLikeComplex = Any diff --git a/apax/layers/properties.py b/apax/layers/properties.py index 44dee1d8..8889314c 100644 --- a/apax/layers/properties.py +++ b/apax/layers/properties.py @@ -1,6 +1,6 @@ import jax import jax.numpy as jnp -from jax_md.util import Array +from jax import Array def stress_times_vol(energy_fn, position: Array, box, **kwargs) -> Array: diff --git a/apax/md/io.py b/apax/md/io.py index 6b421445..2f1b0321 100644 --- a/apax/md/io.py +++ b/apax/md/io.py @@ -6,7 +6,7 @@ import znh5md from ase import Atoms from ase.calculators.singlepoint import SinglePointCalculator -from jax_md.space import transform +from apax.utils.jax_md_reduced.space import transform from apax.md.sim_utils import System diff --git a/apax/md/sim_utils.py b/apax/md/sim_utils.py index 587856fc..abcfcbe2 100644 --- a/apax/md/sim_utils.py +++ b/apax/md/sim_utils.py @@ -3,7 +3,7 @@ import jax.numpy as jnp import numpy as np -from jax_md.space import transform +from apax.utils.jax_md_reduced.space import transform @dataclasses.dataclass diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index f0b26d54..0b6d55e4 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -6,8 +6,7 @@ import jax import jax.numpy as jnp import numpy as np -from jax import vmap -from jax_md.util import Array +from jax import vmap, Array from apax.layers.descriptor.gaussian_moment_descriptor import GaussianMomentDescriptor from apax.layers.empirical import EmpiricalEnergyTerm diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py index 7dd072d4..4d757aed 100644 --- a/apax/utils/jax_md_reduced/space.py +++ b/apax/utils/jax_md_reduced/space.py @@ -16,7 +16,7 @@ import jax.numpy as jnp from jax import custom_jvp, vmap -from jax_md import space +# from jax_md import space from apax.utils.jax_md_reduced.util import Array, f32, f64, safe_mask diff --git a/apax/utils/math.py b/apax/utils/math.py index edb97610..93e4967b 100644 --- a/apax/utils/math.py +++ b/apax/utils/math.py @@ -1,7 +1,7 @@ from typing import Iterable, Optional, Union import jax.numpy as jnp -from jax_md.util import Array +from jax import Array def fp64_sum( diff --git a/poetry.lock b/poetry.lock index 587cf5cd..de96f0d8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,13 +13,13 @@ files = [ [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] @@ -84,24 +84,6 @@ files = [ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" -[[package]] -name = "attrs" -version = "23.1.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - [[package]] name = "babel" version = "2.14.0" @@ -118,19 +100,22 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -181,24 +166,24 @@ files = [ [[package]] name = "cachetools" -version = "5.3.2" +version = "5.3.3" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, - {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, + {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, + {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, ] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -569,17 +554,6 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] -[[package]] -name = "dataclasses" -version = "0.6" -description = "A backport of the dataclasses module for Python 3.6" -optional = false -python-versions = "*" -files = [ - {file = "dataclasses-0.6-py3-none-any.whl", hash = "sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f"}, - {file = "dataclasses-0.6.tar.gz", hash = "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"}, -] - [[package]] name = "distlib" version = "0.3.8" @@ -591,27 +565,6 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] -[[package]] -name = "dm-haiku" -version = "0.0.11" -description = "Haiku is a library for building neural networks in JAX." -optional = false -python-versions = "*" -files = [ - {file = "dm-haiku-0.0.11.tar.gz", hash = "sha256:c420a90c6a76c1d941996698840089df0d352806312eaf7b737486f6c6a32ef2"}, - {file = "dm_haiku-0.0.11-py3-none-any.whl", hash = "sha256:4cac556a9d0e41758abda66bef5ff9dbb36e409c8cfc2b6f20247bc7d39ae45b"}, -] - -[package.dependencies] -absl-py = ">=0.7.1" -flax = ">=0.7.1" -jmp = ">=0.0.2" -numpy = ">=1.18.0" -tabulate = ">=0.8.9" - -[package.extras] -jax = ["jax (>=0.4.16)", "jaxlib (>=0.4.16)"] - [[package]] name = "dm-tree" version = "0.1.8" @@ -671,27 +624,6 @@ files = [ {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, ] -[[package]] -name = "e3nn-jax" -version = "0.20.4" -description = "Equivariant convolutional neural networks for the group E(3) of 3 dimensional rotations, translations, and mirrors." -optional = false -python-versions = ">=3.9" -files = [ - {file = "e3nn-jax-0.20.4.tar.gz", hash = "sha256:3dab5099d845c44050ad7cdeb71434df15f42f8946c05f44e2ede37f0120e797"}, - {file = "e3nn_jax-0.20.4-py3-none-any.whl", hash = "sha256:839b4664ce4a09228fd264ad9cbfe879adc591faa4534ae747962dafd04c6607"}, -] - -[package.dependencies] -attrs = "*" -jax = "*" -jaxlib = "*" -numpy = "*" -sympy = "*" - -[package.extras] -dev = ["dm-haiku", "flax", "jraph", "kaleido", "nox", "optax", "plotly", "pytest", "s2fft", "tqdm"] - [[package]] name = "einops" version = "0.6.1" @@ -705,13 +637,13 @@ files = [ [[package]] name = "etils" -version = "1.6.0" +version = "1.7.0" description = "Collection of common python utils" optional = false python-versions = ">=3.10" files = [ - {file = "etils-1.6.0-py3-none-any.whl", hash = "sha256:3da192b057929f2511f9ef713cee7d9c498e741740f8b2a9c0f6392d787201d4"}, - {file = "etils-1.6.0.tar.gz", hash = "sha256:c635fbd02a79fed4ad76825d31306b581d22b40671721daa8bc279cf6333e48a"}, + {file = "etils-1.7.0-py3-none-any.whl", hash = "sha256:61af8f7c242171de15e22e5da02d527cb9e677d11f8bcafe18fcc3548eee3e60"}, + {file = "etils-1.7.0.tar.gz", hash = "sha256:97b68fd25e185683215286ef3a54e38199b6245f5fe8be6bedc1189be4256350"}, ] [package.dependencies] @@ -814,13 +746,13 @@ files = [ [[package]] name = "flax" -version = "0.7.5" +version = "0.8.1" description = "Flax: A neural network library for JAX designed for flexibility" optional = false python-versions = ">=3.9" files = [ - {file = "flax-0.7.5-py3-none-any.whl", hash = "sha256:bb8cf313e4935089e222fe676e09ea96e9b4d2f9ad355f8acff37c2ca5640d08"}, - {file = "flax-0.7.5.tar.gz", hash = "sha256:f51043efd60eb194dd4648c778ae3ea291ef3fd03ec975dce69d98de7ca47489"}, + {file = "flax-0.8.1-py3-none-any.whl", hash = "sha256:8cf9ef11859eef252470377556a8cc48db287fc6647407ab34f1fc01461925dd"}, + {file = "flax-0.8.1.tar.gz", hash = "sha256:ce3d99e9b4c0d2e4d9fc28bc56cced8ba953adfd695aabd24f096b4c8a7e2f92"}, ] [package.dependencies] @@ -839,64 +771,64 @@ typing-extensions = ">=4.2" [package.extras] all = ["matplotlib"] -testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9)", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "nbstripout", "opencv-python", "pytest", "pytest-cov", "pytest-custom-exit-code", "pytest-xdist (==1.34.0)", "pytype", "sentencepiece", "tensorflow", "tensorflow-datasets", "tensorflow-text (>=2.11.0)", "torch"] +testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9)", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "nbstripout", "opencv-python", "pytest", "pytest-cov", "pytest-custom-exit-code", "pytest-xdist", "pytype", "sentencepiece", "tensorflow", "tensorflow-datasets", "tensorflow-text (>=2.11.0)", "torch"] [[package]] name = "fonttools" -version = "4.47.0" +version = "4.49.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, - {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, - {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, - {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, - {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, - {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, - {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, - {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, - {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, - {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, - {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, - {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, - {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, -] - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"}, + {file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"}, + {file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"}, + {file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"}, + {file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"}, + {file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"}, + {file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"}, + {file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"}, + {file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"}, + {file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"}, + {file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"}, + {file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"}, + {file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] @@ -908,13 +840,13 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "fsspec" -version = "2023.12.2" +version = "2024.2.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2023.12.2-py3-none-any.whl", hash = "sha256:d800d87f72189a745fa3d6b033b9dc4a34ad069f60ca60b943a63599f5501960"}, - {file = "fsspec-2023.12.2.tar.gz", hash = "sha256:8548d39e8810b59c38014934f6b31e57f40c1b20f911f4cc2b85389c7e9bf0cb"}, + {file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8"}, + {file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84"}, ] [package.extras] @@ -932,7 +864,7 @@ github = ["requests"] gs = ["gcsfs"] gui = ["panel"] hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] libarchive = ["libarchive-c"] oci = ["ocifs"] s3 = ["s3fs"] @@ -971,13 +903,13 @@ files = [ [[package]] name = "google-auth" -version = "2.25.2" +version = "2.28.1" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.25.2.tar.gz", hash = "sha256:42f707937feb4f5e5a39e6c4f343a17300a459aaf03141457ba505812841cc40"}, - {file = "google_auth-2.25.2-py2.py3-none-any.whl", hash = "sha256:473a8dfd0135f75bb79d878436e568f2695dce456764bf3a02b6f8c540b1d256"}, + {file = "google-auth-2.28.1.tar.gz", hash = "sha256:34fc3046c257cedcf1622fc4b31fc2be7923d9b4d44973d481125ecc50d83885"}, + {file = "google_auth-2.28.1-py2.py3-none-any.whl", hash = "sha256:25141e2d7a14bfcba945f5e9827f98092716e99482562f15306e5b026e21aa72"}, ] [package.dependencies] @@ -1044,69 +976,69 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpcio" -version = "1.60.0" +version = "1.62.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] + {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, + {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, + {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, + {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, + {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, + {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, + {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, + {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, + {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, + {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, + {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, + {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, + {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, + {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, + {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, + {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, + {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, + {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, + {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, + {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, + {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, + {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, + {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, + {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.62.0)"] [[package]] name = "h5py" @@ -1147,13 +1079,13 @@ numpy = ">=1.17.3" [[package]] name = "identify" -version = "2.5.33" +version = "2.5.35" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, + {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, ] [package.extras] @@ -1183,18 +1115,18 @@ files = [ [[package]] name = "importlib-resources" -version = "6.1.1" +version = "6.1.2" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, + {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, + {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1223,13 +1155,13 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jax" -version = "0.4.23" +version = "0.4.25" description = "Differentiate, compile, and transform Numpy code." optional = false python-versions = ">=3.9" files = [ - {file = "jax-0.4.23-py3-none-any.whl", hash = "sha256:a7a07ccd1577111e3b82378c79a8ed0f9d6613b1e98fb6bf3c0b459198f73eaa"}, - {file = "jax-0.4.23.tar.gz", hash = "sha256:2a229a5a758d1b803891b2eaed329723f6b15b4258b14dc0ccb1498c84963685"}, + {file = "jax-0.4.25-py3-none-any.whl", hash = "sha256:8158c837e5ecc195074b421609e85329a962785b36f9fe5ff53e844e8ad87dbc"}, + {file = "jax-0.4.25.tar.gz", hash = "sha256:a8ee189c782de2b7b2ffb64a8916da380b882a617e2769aa429b71d79747b982"}, ] [package.dependencies] @@ -1243,74 +1175,45 @@ scipy = ">=1.9" [package.extras] australis = ["protobuf (>=3.13,<4)"] -ci = ["jaxlib (==0.4.22)"] -cpu = ["jaxlib (==0.4.23)"] -cuda = ["jaxlib (==0.4.23+cuda11.cudnn86)"] -cuda11-cudnn86 = ["jaxlib (==0.4.23+cuda11.cudnn86)"] -cuda11-local = ["jaxlib (==0.4.23+cuda11.cudnn86)"] -cuda11-pip = ["jaxlib (==0.4.23+cuda11.cudnn86)", "nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)", "nvidia-nccl-cu11 (>=2.18.3)"] -cuda12 = ["jax-cuda12-plugin (==0.4.23)", "jaxlib (==0.4.23)", "nvidia-cublas-cu12 (>=12.2.5.6)", "nvidia-cuda-cupti-cu12 (>=12.2.142)", "nvidia-cuda-nvcc-cu12 (>=12.2.140)", "nvidia-cuda-runtime-cu12 (>=12.2.140)", "nvidia-cudnn-cu12 (>=8.9)", "nvidia-cufft-cu12 (>=11.0.8.103)", "nvidia-cusolver-cu12 (>=11.5.2)", "nvidia-cusparse-cu12 (>=12.1.2.141)", "nvidia-nccl-cu12 (>=2.18.3)", "nvidia-nvjitlink-cu12 (>=12.2)"] -cuda12-local = ["jaxlib (==0.4.23+cuda12.cudnn89)"] -cuda12-pip = ["jaxlib (==0.4.23+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.2.5.6)", "nvidia-cuda-cupti-cu12 (>=12.2.142)", "nvidia-cuda-nvcc-cu12 (>=12.2.140)", "nvidia-cuda-runtime-cu12 (>=12.2.140)", "nvidia-cudnn-cu12 (>=8.9)", "nvidia-cufft-cu12 (>=11.0.8.103)", "nvidia-cusolver-cu12 (>=11.5.2)", "nvidia-cusparse-cu12 (>=12.1.2.141)", "nvidia-nccl-cu12 (>=2.18.3)", "nvidia-nvjitlink-cu12 (>=12.2)"] -minimum-jaxlib = ["jaxlib (==0.4.19)"] -tpu = ["jaxlib (==0.4.23)", "libtpu-nightly (==0.1.dev20231213)", "requests"] - -[[package]] -name = "jax-md" -version = "0.2.8" -description = "" -optional = false -python-versions = ">=3.9" -files = [] -develop = false - -[package.dependencies] -absl-py = "*" -dataclasses = "*" -dm-haiku = "*" -e3nn-jax = "*" -einops = "*" -flax = "*" -jax = "*" -jaxlib = "*" -jraph = "*" -ml_collections = "*" -numpy = "*" -optax = "*" - -[package.source] -type = "git" -url = "https://github.com/jax-md/jax-md.git" -reference = "HEAD" -resolved_reference = "a4851b841523789e1202773b12c3b68f2dfb7fd5" +ci = ["jaxlib (==0.4.24)"] +cpu = ["jaxlib (==0.4.25)"] +cuda = ["jaxlib (==0.4.25+cuda11.cudnn86)"] +cuda11-cudnn86 = ["jaxlib (==0.4.25+cuda11.cudnn86)"] +cuda11-local = ["jaxlib (==0.4.25+cuda11.cudnn86)"] +cuda11-pip = ["jaxlib (==0.4.25+cuda11.cudnn86)", "nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)", "nvidia-nccl-cu11 (>=2.18.3)"] +cuda12 = ["jax-cuda12-plugin (==0.4.25)", "jaxlib (==0.4.25)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] +cuda12-local = ["jaxlib (==0.4.25+cuda12.cudnn89)"] +cuda12-pip = ["jaxlib (==0.4.25+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] +minimum-jaxlib = ["jaxlib (==0.4.20)"] +tpu = ["jaxlib (==0.4.25)", "libtpu-nightly (==0.1.dev20240224)", "requests"] [[package]] name = "jaxlib" -version = "0.4.23" +version = "0.4.25" description = "XLA library for JAX" optional = false python-versions = ">=3.9" files = [ - {file = "jaxlib-0.4.23-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:e3756e0601af7636ae58f42d24af70e46048ffef89bd5e05c303b899a2177c36"}, - {file = "jaxlib-0.4.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fdb1b791e3ee17cad44460b3f42c9a61a86910a877229d30bd3654f4463d5a0"}, - {file = "jaxlib-0.4.23-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a3de5e061a173f434fd1b88074f1610e4e881ff712ff3be61e655bae2fab8ea0"}, - {file = "jaxlib-0.4.23-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:7275fbe5a489c683c5502603d55e508323cda2f4bd9521aa8383c674fb0ab2f3"}, - {file = "jaxlib-0.4.23-cp310-cp310-win_amd64.whl", hash = "sha256:f774941542aa8fd866e4c860082aebdd17c34ea35c2a6a74e46631b6fb377a99"}, - {file = "jaxlib-0.4.23-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:8e12d7e29b3e12d535b24bbbdb6bf9d66cf64926a6a38fdd91d4565f7cc57111"}, - {file = "jaxlib-0.4.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d646ff9bc0ce0ebb573b676b21fa6db422c2ef6a0d56ccc00db483b29965415b"}, - {file = "jaxlib-0.4.23-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:22fb2c2b76276d396ddb1edfe41c6d943216f04fa8c00638b16d6c56cad403b8"}, - {file = "jaxlib-0.4.23-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:984766d309b21ca83846503babdfded4e3aef817c670f281092bcbc177c58492"}, - {file = "jaxlib-0.4.23-cp311-cp311-win_amd64.whl", hash = "sha256:99c345b9e58c158e5fe6c621084aa1fdf7eb9eb9172c27729918d20272124ea8"}, - {file = "jaxlib-0.4.23-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:505104fe6062b443955288a38547e9872cb6e107d63d9f8540fb10d1c8d8efd0"}, - {file = "jaxlib-0.4.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:278cda29cc7473406093bc3f9fa925a8396063d22a4cd20d7e0ea0d37dcb5039"}, - {file = "jaxlib-0.4.23-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:b33bc2f8a2163801941d4316fad095778fe32f5519d8d146e6e4504e6a82fe7d"}, - {file = "jaxlib-0.4.23-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:a229a2b90a2980dd682a16c373b4ac4493e703a262108f5489e8a4591daaa559"}, - {file = "jaxlib-0.4.23-cp312-cp312-win_amd64.whl", hash = "sha256:ce7dd9295ccdac6a4739b4a344caa1ea2e555e686216b74313ec7562b00695f0"}, - {file = "jaxlib-0.4.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4dd538c04a2a121b03ab5f0cb8b12998aaa9539d7ec54629feb799a840c92b55"}, - {file = "jaxlib-0.4.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81d6f4edcd761c27cae555d3d82fbd958292888a4f803f2c366778786d8ce8ce"}, - {file = "jaxlib-0.4.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c78d2accacb34da96ccd7fd2a7e87ed3e93ba74af40c2b2b19e09289fe3381cf"}, - {file = "jaxlib-0.4.23-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:99a37d4732bafe1608b8f45df27f27e6a6bf1f23e001fe940fe9a5ab3675fd77"}, - {file = "jaxlib-0.4.23-cp39-cp39-win_amd64.whl", hash = "sha256:fdf8920a8b00d3e4574978e799c865615132df75f6579e4eec0c50e105df6c66"}, + {file = "jaxlib-0.4.25-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:be1b26e96e80d42f54f77226a016717cb969d7d208d0dcb61997f19dc7b2d8e2"}, + {file = "jaxlib-0.4.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3b5cbd3a4f731636469cdaf06c4413208811ca458ee312647e8f3faca32f6445"}, + {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:89a011330aaeaf19027bba5e3236be155cc8d73d94aa9db84d817d414f4a7647"}, + {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:dcda74c7c8eb328cde8afeebcf21ec9240138fac54f9631a60b679a211f7e100"}, + {file = "jaxlib-0.4.25-cp310-cp310-win_amd64.whl", hash = "sha256:fd751b10e60c085dec42bec6c27c9905f5c57d12323190eea0df10ee14c574e0"}, + {file = "jaxlib-0.4.25-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:37da780cb545ca210bfa0402b5081452ad830bb06fe9e970fd16ad14d2fdc6a6"}, + {file = "jaxlib-0.4.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df7e2193b216e195dfc7a8aa14527eb52614ec3ba4c59a199af2f17195ae1c1"}, + {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:0ce2a25263e7504d575e8ba5ba4f53aef6fe274679785bcf87ab06b0aaec0b90"}, + {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:a0dd09cbb62583941872b6a198894e87a1b64d8e4dd6b53946dbb41d642b8f5f"}, + {file = "jaxlib-0.4.25-cp311-cp311-win_amd64.whl", hash = "sha256:dfb1ef8c2e6a01ecb60f8833552ff077cd593154fd75739050fba9148879a2a4"}, + {file = "jaxlib-0.4.25-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:425d6f3fa57ea1d1674ae84b5a3d3588ba0937f3c47fd4f166eb84c4240887b8"}, + {file = "jaxlib-0.4.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e97542bbd89f4316d2feb599119d8a43440ca151b7a165eff0fc127cf4512e7"}, + {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:c4e3bc32aea275e025e762612216954626478c9cf5c44131e248cdd17e361efd"}, + {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:dcfb71a7f559c13734584769ca30373bc4b73d0fe105790462370e49f35dcbe4"}, + {file = "jaxlib-0.4.25-cp312-cp312-win_amd64.whl", hash = "sha256:f7aa9682b6806e4197ad51294e87e77f04f5eee7ced4e841aa7ccc7320c6d96b"}, + {file = "jaxlib-0.4.25-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:6660b68741286bd4b849c149d86a8c36e448f7e39e1d483e79dab79ea300bf1b"}, + {file = "jaxlib-0.4.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32881f93d5de195a0fd19e091a2aa89418fa27f630d30c79b4613a51cff4d1c6"}, + {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ad1ab653265c33b8d54bdcc40867a8ffd61fea879176e4d4cd0b585fe52521fc"}, + {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:0fd113ab414de856f90f07264e6ccd0cb95d392f3579c0deab4ff0943ef75f73"}, + {file = "jaxlib-0.4.25-cp39-cp39-win_amd64.whl", hash = "sha256:b11aef2bd6cf873b39399fda122170b625776d977bbc56b4635f46c396279b8b"}, ] [package.dependencies] @@ -1340,13 +1243,13 @@ typing-extensions = ">=3.7.4.1" [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1355,43 +1258,6 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] -[[package]] -name = "jmp" -version = "0.0.4" -description = "JMP is a Mixed Precision library for JAX." -optional = false -python-versions = "*" -files = [ - {file = "jmp-0.0.4-py3-none-any.whl", hash = "sha256:6aa7adbddf2bd574b28c7faf6e81a735eb11f53386447896909c6968dc36807d"}, - {file = "jmp-0.0.4.tar.gz", hash = "sha256:5dfeb0fd7c7a9f72a70fff0aab9d0cbfae32a809c02f4037ff3485ceb33e1730"}, -] - -[package.dependencies] -numpy = ">=1.19.5" - -[package.extras] -jax = ["jax (>=0.2.20)", "jaxlib (>=0.1.71)"] - -[[package]] -name = "jraph" -version = "0.0.6.dev0" -description = "Jraph: A library for Graph Neural Networks in Jax" -optional = false -python-versions = ">=3.6" -files = [ - {file = "jraph-0.0.6.dev0-py3-none-any.whl", hash = "sha256:350fe37bf717f934f1f84fd3370a480b3178bfcb61dfa217c738971308c57625"}, - {file = "jraph-0.0.6.dev0.tar.gz", hash = "sha256:c3ac3a0b224b344eb6d367e8bc312d95ea41bf825d01ea31b80dd8c22c0dd8b8"}, -] - -[package.dependencies] -jax = ">=0.1.55" -jaxlib = ">=0.1.37" -numpy = ">=1.18.0" - -[package.extras] -examples = ["absl-py (>=0.9)", "dm-haiku (>=0.0.2)", "frozendict (>=2.0.2)", "optax (>=0.0.1)", "scipy (>=1.2.1)"] -ogb-examples = ["absl-py (>=0.9)", "dm-haiku (>=0.0.2)", "dm-tree (>=0.1.5)", "optax (>=0.0.1)", "pandas (>=1.0.5)"] - [[package]] name = "keras" version = "2.15.0" @@ -1551,15 +1417,26 @@ files = [ {file = "libclang-16.0.6.tar.gz", hash = "sha256:4acdde39dfe410c877b4ccc0d4b57eb952100e4ee26bbdf6cfdb88e2033a7d31"}, ] +[[package]] +name = "looseversion" +version = "1.3.0" +description = "Version numbering for anarchists and software realists" +optional = false +python-versions = "*" +files = [ + {file = "looseversion-1.3.0-py2.py3-none-any.whl", hash = "sha256:781ef477b45946fc03dd4c84ea87734b21137ecda0e1e122bcb3c8d16d2a56e0"}, + {file = "looseversion-1.3.0.tar.gz", hash = "sha256:ebde65f3f6bb9531a81016c6fef3eb95a61181adc47b7f949e9c0ea47911669e"}, +] + [[package]] name = "markdown" -version = "3.5.1" +version = "3.5.2" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, - {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, + {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, + {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] [package.extras] @@ -1592,98 +1469,108 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.8.3" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, + {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, + {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, + {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, + {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, + {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, + {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, + {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, + {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, + {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, ] [package.dependencies] @@ -1699,46 +1586,42 @@ python-dateutil = ">=2.7" [[package]] name = "matscipy" -version = "0.8.0" +version = "0.8.1" description = "Generic Python Materials Science tools" optional = false python-versions = ">=3.7.0" files = [ - {file = "matscipy-0.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2793c24058465758ef03747ab2d2d4a5015b96d81401c9f6bd5a7456143390b"}, - {file = "matscipy-0.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cc53ac66cc061ecb635255eded75691488b0e13a2fdd0764f4e36c013f3e300c"}, - {file = "matscipy-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0525ed8393c2e800d9e63447b70c22e5ce3a5a7e3b4d90298829dcc43062d5b"}, - {file = "matscipy-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8e4ea06726df0342705808775055be54d73af2bdb663b8d83ca0789eb6d712"}, - {file = "matscipy-0.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aee19e1822b0fc02c7b74c775ef9b602c0a867730aa2c087cd244f32c2208cea"}, - {file = "matscipy-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:360cad44d1c5fe07a9220338987f31d3ba63f2c031151937321c297a7e1e0719"}, - {file = "matscipy-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5c185b7a53a447a7e54f01caba298354560f14744a53c62a1f13442f72cb75d4"}, - {file = "matscipy-0.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:445414d10006e46f4732a590e164e5a4e5586052ae1d4e9555baca409978a064"}, - {file = "matscipy-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b31d4d5414a6436c653ad98db8b28c8a0e78e2bc426c9358c4f8fa6d88253e2"}, - {file = "matscipy-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93bcd26b0c7a522fdd05d620828fb6d92a69831b06ee28736b2d8c8c0b233fbc"}, - {file = "matscipy-0.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1aa882e27a446ad03a00b0ffdf7b387ec4ffce1ad944c4d4c6c02906a0e5765e"}, - {file = "matscipy-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a37187285d21455b096882f23018c3a0f2fb68723ca0484e4dd8c740e56e602d"}, - {file = "matscipy-0.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82de2474e2be3fa464265d6d1327c18e3e7542fc1cf8c09e4115019faeb4ff00"}, - {file = "matscipy-0.8.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:aa603724d7f99d8e1288a552f7d36907ee26a4ad2b349be44a4d2279c2a23074"}, - {file = "matscipy-0.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:238491e088b6f9643f6134e5690daa10307e433a88f701cb943aa57bb8c58926"}, - {file = "matscipy-0.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afed8c57022b0e6514c4e4e95427c6260c223a8755a228aacfb94eefd71a1772"}, - {file = "matscipy-0.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0765f1911209e37ce84fb7cf2014ccbd01f2d8f1d280aee647bde07efcaee90e"}, - {file = "matscipy-0.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5b42b60e97d178f191afb5451ed6391a8c046463191a94058d0e87f78072181"}, - {file = "matscipy-0.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d3af56774bbfbaa7118793af8f4a7affec10d07631e937dd6f2fda7425924d9"}, - {file = "matscipy-0.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:1111a259760aa0449aa070c60de95645430ffd43e264457d2b71477bcc9f91a5"}, - {file = "matscipy-0.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4daaf2a413f48fc2c29df577304af0fe846b472ebde1b56056f31fd1a7865854"}, - {file = "matscipy-0.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c5f4b6e4824cfbf0b4a85e0ef63e014d240943cc02dba48efb4dc591e9da9e3"}, - {file = "matscipy-0.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5b8ba7354580bd928da22214659fef514763579f472e14a8c9a1246b9bb31cf6"}, - {file = "matscipy-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:b14c8c50935b61ceefffcc0e25a68c15fca058afaff458dd40ba58e785d58e38"}, - {file = "matscipy-0.8.0.tar.gz", hash = "sha256:c6284e9d74cbcc30d705d9c6d02d84b7dbfa15fe07b9f7358ed8c2b525c7026f"}, + {file = "matscipy-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d61de79c9e7a6f2861ba4ec41f257fddc1dd60ed692431039fa31ec58dc8bcce"}, + {file = "matscipy-0.8.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:fde340e90a522ad5ad7b7a011bbb81ee6c93889ccf47fb01cf74ab376e4c1a85"}, + {file = "matscipy-0.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd2845247b23f339ff05b0e94bf98f71a1888ea116bcb48f93f46019b58da41f"}, + {file = "matscipy-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:e24a188b752d0f8dfea9eb6b5b37d3bc0c94de853ea03a2832d79133653cd649"}, + {file = "matscipy-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17189e8a9a819be52ac48cf406de4abef03cd2657815d315902f99bfed828c3f"}, + {file = "matscipy-0.8.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b38d101eb050eb7203aa53e2a1a097ee693c36c5d6ccb346c0e180198ecec226"}, + {file = "matscipy-0.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e43eb9166a43d290ecde195f79fe932f6577b43f5431a5046403180296f9a9"}, + {file = "matscipy-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:350c2d29c865eea5ecd5ad6b7a68df1523c3fa44bac1ebd738ec36b5f62e520e"}, + {file = "matscipy-0.8.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7ad3994896e3c2319b7ef009d49a83c18f86038c572278511459c76f89f230bd"}, + {file = "matscipy-0.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f01005626f7efc0661df7b2bc3efa3825b807db864f2e2bf8901e70132159811"}, + {file = "matscipy-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:1afa3285da5c01a3671beb2991bc0fdf9cdd24fe85c23d4cfbf2b92d41564bd1"}, + {file = "matscipy-0.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5996df13442fae456da3dcff2ec9322640bdb2beea54bcbc49f3973816762d7"}, + {file = "matscipy-0.8.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a3cedf79bdacd1f0c106e6dfeab6e35523822041a2dc56a32dd1e2a00f5767a5"}, + {file = "matscipy-0.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79cbfdd46b1560cf67f8000714483ff2299c73c0a8f0772c489457d670fda6c9"}, + {file = "matscipy-0.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:0c04da749239d79056894b0b5a3aa5aa5a0f3d935c7781c43123f4d1b21c8184"}, + {file = "matscipy-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0a3be6e092ec9c5c5dfd139e6bdf2c606d29a393aa1f3cae38d27fe29b7cfee4"}, + {file = "matscipy-0.8.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:dc364220b04544ae698ebf8c4c640fe3b7add981b5a477b44935fdd97a61d322"}, + {file = "matscipy-0.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4829b49710eb89eac44b16f89549f3bd343769486ec8071f27444c7f452c147d"}, + {file = "matscipy-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:248dc5620219300f87f7ab66b4ca71b4bfe0ef5c3288807c20e609ec04376794"}, + {file = "matscipy-0.8.1.tar.gz", hash = "sha256:078dabf4574cd74c08789e956516dca94e3d49cd5f27f044418af36b7275a063"}, ] [package.dependencies] ase = ">=3.16.0" +looseversion = "*" numpy = ">=1.16.0" scipy = ">=1.2.3" [package.extras] -docs = ["sphinx", "sphinx-rtd-theme"] -test = ["pytest", "sympy"] +docs = ["atomman", "myst_nb", "nglview", "numpydoc", "ovito", "pydata-sphinx-theme", "sphinx", "sphinx_copybutton", "sphinx_rtd_theme"] +test = ["atomman", "ovito", "pytest", "sympy"] [[package]] name = "mccabe" @@ -1832,23 +1715,6 @@ numpy = [ [package.extras] dev = ["absl-py", "pyink", "pylint (>=2.6.0)", "pytest", "pytest-xdist"] -[[package]] -name = "mpmath" -version = "1.3.0" -description = "Python library for arbitrary-precision floating-point arithmetic" -optional = false -python-versions = "*" -files = [ - {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, - {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, -] - -[package.extras] -develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] -docs = ["sphinx"] -gmpy = ["gmpy2 (>=2.1.0a4)"] -tests = ["pytest (>=4.6)"] - [[package]] name = "msgpack" version = "1.0.7" @@ -1953,13 +1819,13 @@ testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4, [[package]] name = "nest-asyncio" -version = "1.5.8" +version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" files = [ - {file = "nest_asyncio-1.5.8-py3-none-any.whl", hash = "sha256:accda7a339a70599cb08f9dd09a67e0c2ef8d8d6f4c07f96ab203f2ae254e48d"}, - {file = "nest_asyncio-1.5.8.tar.gz", hash = "sha256:25aa2ca0d2a5b5531956b9e273b45cf664cae2b145101d73b86b199978d48fdb"}, + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, ] [[package]] @@ -1978,47 +1844,47 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.26.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, - {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, - {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, - {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, - {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, - {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, - {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, - {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, - {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, - {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, - {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -2057,24 +1923,24 @@ tests = ["pytest", "pytest-cov", "pytest-pep8"] [[package]] name = "optax" -version = "0.1.7" +version = "0.1.9" description = "A gradient processing and optimisation library in JAX." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "optax-0.1.7-py3-none-any.whl", hash = "sha256:2b85115f2ae7adafe5fd9abf4b275e53057765361511c8ccc868e70158458494"}, - {file = "optax-0.1.7.tar.gz", hash = "sha256:6a5a848bc5e55e619b187c749fdddc4a5443ea14be85cc769f995779865c110d"}, + {file = "optax-0.1.9-py3-none-any.whl", hash = "sha256:3cbcfac6e70dff9484cd7560dc92e43a50df1eac0d4af2a1f7c2e1fd116bf972"}, + {file = "optax-0.1.9.tar.gz", hash = "sha256:731f43e8b404f50a5ef025b1261894d7d0300f7ad9cb688ea08f67b40822e94f"}, ] [package.dependencies] absl-py = ">=0.7.1" -chex = ">=0.1.5" +chex = ">=0.1.7" jax = ">=0.1.55" jaxlib = ">=0.1.37" numpy = ">=1.18.0" [package.extras] -docs = ["IPython (==7.16.3)", "dm-haiku (==0.0.8)", "docutils (==0.16)", "ipykernel (==5.3.4)", "matplotlib (==3.5.0)", "myst_nb (==0.13.1)", "pandoc (==1.0.2)", "sphinx (==4.5.0)", "sphinx-autodoc-typehints (==1.11.1)", "sphinx-book-theme (==0.3.3)", "sphinxcontrib-bibtex (==2.4.2)", "sphinxcontrib-katex (==0.9.0)"] +docs = ["dm-haiku (>=0.0.11)", "ipython (>=8.8.0)", "matplotlib (>=3.5.0)", "myst-nb (>=1.0.0)", "sphinx (>=6.0.0)", "sphinx-autodoc-typehints", "sphinx-book-theme (>=1.0.1)", "sphinx-collections (>=0.0.1)", "sphinx-gallery (>=0.14.0)", "sphinxcontrib-katex", "tensorflow (>=2.4.0)", "tensorflow-datasets (>=4.2.0)"] dp-accounting = ["absl-py (>=1.0.0)", "attrs (>=21.4.0)", "mpmath (>=1.2.1)", "numpy (>=1.21.4)", "scipy (>=1.7.1)"] examples = ["dm-haiku (>=0.0.3)", "tensorflow (>=2.4.0)", "tensorflow-datasets (>=4.2.0)"] test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] @@ -2130,95 +1996,113 @@ files = [ [[package]] name = "pillow" -version = "10.1.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, - {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, - {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, - {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, - {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, - {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, - {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, - {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, ] [package.extras] docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -2292,27 +2176,27 @@ files = [ [[package]] name = "psutil" -version = "5.9.7" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, - {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, - {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, - {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, - {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, - {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, - {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, - {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, - {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, - {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] @@ -2356,18 +2240,18 @@ files = [ [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.2" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, + {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -2375,116 +2259,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.3" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -2532,13 +2390,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -2726,61 +2584,61 @@ pyasn1 = ">=0.1.3" [[package]] name = "scipy" -version = "1.11.4" +version = "1.12.0" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "scipy-1.11.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc9a714581f561af0848e6b69947fda0614915f072dfd14142ed1bfe1b806710"}, - {file = "scipy-1.11.4-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cf00bd2b1b0211888d4dc75656c0412213a8b25e80d73898083f402b50f47e41"}, - {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9999c008ccf00e8fbcce1236f85ade5c569d13144f77a1946bef8863e8f6eb4"}, - {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:933baf588daa8dc9a92c20a0be32f56d43faf3d1a60ab11b3f08c356430f6e56"}, - {file = "scipy-1.11.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8fce70f39076a5aa62e92e69a7f62349f9574d8405c0a5de6ed3ef72de07f446"}, - {file = "scipy-1.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:6550466fbeec7453d7465e74d4f4b19f905642c89a7525571ee91dd7adabb5a3"}, - {file = "scipy-1.11.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f313b39a7e94f296025e3cffc2c567618174c0b1dde173960cf23808f9fae4be"}, - {file = "scipy-1.11.4-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1b7c3dca977f30a739e0409fb001056484661cb2541a01aba0bb0029f7b68db8"}, - {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00150c5eae7b610c32589dda259eacc7c4f1665aedf25d921907f4d08a951b1c"}, - {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:530f9ad26440e85766509dbf78edcfe13ffd0ab7fec2560ee5c36ff74d6269ff"}, - {file = "scipy-1.11.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e347b14fe01003d3b78e196e84bd3f48ffe4c8a7b8a1afbcb8f5505cb710993"}, - {file = "scipy-1.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:acf8ed278cc03f5aff035e69cb511741e0418681d25fbbb86ca65429c4f4d9cd"}, - {file = "scipy-1.11.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:028eccd22e654b3ea01ee63705681ee79933652b2d8f873e7949898dda6d11b6"}, - {file = "scipy-1.11.4-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c6ff6ef9cc27f9b3db93a6f8b38f97387e6e0591600369a297a50a8e96e835d"}, - {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030c6674b9230d37c5c60ab456e2cf12f6784596d15ce8da9365e70896effc4"}, - {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad669df80528aeca5f557712102538f4f37e503f0c5b9541655016dd0932ca79"}, - {file = "scipy-1.11.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce7fff2e23ab2cc81ff452a9444c215c28e6305f396b2ba88343a567feec9660"}, - {file = "scipy-1.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:36750b7733d960d7994888f0d148d31ea3017ac15eef664194b4ef68d36a4a97"}, - {file = "scipy-1.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e619aba2df228a9b34718efb023966da781e89dd3d21637b27f2e54db0410d7"}, - {file = "scipy-1.11.4-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f3cd9e7b3c2c1ec26364856f9fbe78695fe631150f94cd1c22228456404cf1ec"}, - {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10e45a6c50211fe256da61a11c34927c68f277e03138777bdebedd933712fea"}, - {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91af76a68eeae0064887a48e25c4e616fa519fa0d38602eda7e0f97d65d57937"}, - {file = "scipy-1.11.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6df1468153a31cf55ed5ed39647279beb9cfb5d3f84369453b49e4b8502394fd"}, - {file = "scipy-1.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee410e6de8f88fd5cf6eadd73c135020bfbbbdfcd0f6162c36a7638a1ea8cc65"}, - {file = "scipy-1.11.4.tar.gz", hash = "sha256:90a2b78e7f5733b9de748f589f09225013685f9b218275257f8a8168ededaeaa"}, -] - -[package.dependencies] -numpy = ">=1.21.6,<1.28.0" + {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, + {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, + {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, + {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, + {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, + {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, + {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, + {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, + {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, + {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, + {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, + {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, + {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, + {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, + {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, + {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, + {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, + {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, + {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, + {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, + {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, + {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, + {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, + {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, + {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<1.29.0" [package.extras] dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, + {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shellingham" @@ -2862,22 +2720,22 @@ test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools [[package]] name = "sphinx-autodoc-typehints" -version = "1.25.2" +version = "1.25.3" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.8" files = [ - {file = "sphinx_autodoc_typehints-1.25.2-py3-none-any.whl", hash = "sha256:5ed05017d23ad4b937eab3bee9fae9ab0dd63f0b42aa360031f1fad47e47f673"}, - {file = "sphinx_autodoc_typehints-1.25.2.tar.gz", hash = "sha256:3cabc2537e17989b2f92e64a399425c4c8bf561ed73f087bc7414a5003616a50"}, + {file = "sphinx_autodoc_typehints-1.25.3-py3-none-any.whl", hash = "sha256:d3da7fa9a9761eff6ff09f8b1956ae3090a2d4f4ad54aebcade8e458d6340835"}, + {file = "sphinx_autodoc_typehints-1.25.3.tar.gz", hash = "sha256:70db10b391acf4e772019765991d2de0ff30ec0899b9ba137706dc0b3c4835e0"}, ] [package.dependencies] sphinx = ">=7.1.2" [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)"] +docs = ["furo (>=2023.9.10)"] numpy = ["nptyping (>=2.5)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.7.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.8)"] [[package]] name = "sphinx-basic-ng" @@ -2935,56 +2793,50 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.5" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, + {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -3017,76 +2869,44 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.7" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, + {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] -[[package]] -name = "sympy" -version = "1.12" -description = "Computer algebra system (CAS) in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, - {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, -] - -[package.dependencies] -mpmath = ">=0.19" - -[[package]] -name = "tabulate" -version = "0.9.0" -description = "Pretty-print tabular data" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, - {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, -] - -[package.extras] -widechars = ["wcwidth"] - [[package]] name = "tensorboard" -version = "2.15.1" +version = "2.15.2" description = "TensorBoard lets you watch Tensors Flow" optional = false python-versions = ">=3.9" files = [ - {file = "tensorboard-2.15.1-py3-none-any.whl", hash = "sha256:c46c1d1cf13a458c429868a78b2531d8ff5f682058d69ec0840b0bc7a38f1c0f"}, + {file = "tensorboard-2.15.2-py3-none-any.whl", hash = "sha256:a6f6443728064d962caea6d34653e220e34ef8df764cb06a8212c17e1a8f0622"}, ] [package.dependencies] @@ -3096,7 +2916,7 @@ google-auth-oauthlib = ">=0.5,<2" grpcio = ">=1.48.2" markdown = ">=2.6.8" numpy = ">=1.12.0" -protobuf = ">=3.19.6,<4.24" +protobuf = ">=3.19.6,<4.24.0 || >4.24.0" requests = ">=2.21.0,<3" setuptools = ">=41.0.0" six = ">1.9" @@ -3289,29 +3109,32 @@ files = [ [[package]] name = "tensorflow-io-gcs-filesystem" -version = "0.35.0" +version = "0.36.0" description = "TensorFlow IO" optional = false python-versions = ">=3.7, <3.12" files = [ - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:5521721b38105496d4b43a4ffb0af5b04cc4873d464f26fbceddf8d63815ce98"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd8f30908bf8b7b2a017d6b145720d105aff7f998422671b71729708ec7b2fe4"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac8f1de60fdf9c734aea967b98555e366ac8743f77bca15c49eff023f587076b"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:35b6eca7225c815d962254327195f191d88c3c9c2278a5ab23e0ac834acbadbb"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e997389bfe008210cbd97c0c738d64282a2f03ad4d0536013bb0a9efde0c283"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8fb3402fb1457482c386ea19371bc76383412ae9ea4396edb1e8adb4ba76f21"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb6bf8f5b40207ecb17e7fdc3b4fc824a8361267c14e9528c1688e16de135cb7"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:c4f786eebd98d401565374722f2e67f3878675b0d87489cbaa13c70ee6ac370a"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce1466bdb91096b6d22e7df17358ba228bcb92db5cff83f2f9f1c68eb26788"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1856fe321fdb75f3386d92109c60db6ef097f610b450f9cc69d76444fb9980d1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:702c6df62b38095ff613c433546d9424d4f33902a5ab26b00fd26457e27a99fa"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e9b8aaca2789af356c42afda0f52380f82e5abb2f3c0b85087833fcfe03875d8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c477aed96864ceae77d7051c3b687f28813aba7320fc5dd552164fad6ec8d1a1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be1ff92559dfa23048b01179a1827081947583f5c6f9986ccac471df8a29322a"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:72c3ca4b8c0d8dbdd970699d05a100107cf200317ad8e6a8373e2c37225cd552"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:848e8e89a0f49258c7782189c938d8d1162d989da1a80c79f95c7af3ef6006c8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d72db1ab03edb65fa1e98d06e504ccbc64282d38ab3589afb6db66dc448d1c1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd4d946b5fa23220daa473a80e511a5fb27493d7e49d17dff0bb43bb0a31f32"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa346fd1dd9f57848b73874007440504f060fadd689fa1cc29cc49817d0eeaf3"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0a4437824424a4423cf86162cb8b21b1bec24698194332748b50bb952e62ab9f"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:31806bd7ac2db789161bc720747de22947063265561a4c17be54698fd9780b03"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0e57976c1aa035af6281f0330cfb8dd50eee2f63412ecc84d60ff5075d29b7"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97ff5c280eb10f699098ae21057be2b146d39e8a906cd5db91f2ea6c34e47d0"}, ] [package.extras] -tensorflow = ["tensorflow (>=2.14.0,<2.15.0)"] -tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.14.0,<2.15.0)"] -tensorflow-cpu = ["tensorflow-cpu (>=2.14.0,<2.15.0)"] -tensorflow-gpu = ["tensorflow-gpu (>=2.14.0,<2.15.0)"] -tensorflow-rocm = ["tensorflow-rocm (>=2.14.0,<2.15.0)"] +tensorflow = ["tensorflow (>=2.15.0,<2.16.0)"] +tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.15.0,<2.16.0)"] +tensorflow-cpu = ["tensorflow-cpu (>=2.15.0,<2.16.0)"] +tensorflow-gpu = ["tensorflow-gpu (>=2.15.0,<2.16.0)"] +tensorflow-rocm = ["tensorflow-rocm (>=2.15.0,<2.16.0)"] [[package]] name = "tensorflow-metadata" @@ -3395,24 +3218,24 @@ files = [ [[package]] name = "toolz" -version = "0.12.0" +version = "0.12.1" description = "List processing tools and functional utilities" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" files = [ - {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, - {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, + {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"}, + {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, ] [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, ] [package.dependencies] @@ -3464,40 +3287,41 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.25.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, + {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, ] [package.dependencies] @@ -3652,4 +3476,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "02e6652599fb8121cb7d5fb59e151a32413f31c6a64e05904f147397d62687bf" +content-hash = "ccf786de5155d696622984da7573282ff7f5e5062c9b386610145bf9fcb712b0" diff --git a/pyproject.toml b/pyproject.toml index 217e22bb..5d4717e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ matscipy = "^0.8.0" znh5md = "^0.1.7" pydantic = "^2.3.0" jax = "^0.4.14" -jax-md = {git = "https://github.com/jax-md/jax-md.git"} [tool.poetry.scripts] apax = 'apax.cli.apax_app:app' diff --git a/tests/integration_tests/transfer_learning/test_transfer_learning.py b/tests/integration_tests/transfer_learning/test_transfer_learning.py index 115362bf..c8f3d00c 100644 --- a/tests/integration_tests/transfer_learning/test_transfer_learning.py +++ b/tests/integration_tests/transfer_learning/test_transfer_learning.py @@ -13,8 +13,8 @@ def l2_param_diff(p1, p2): - p1, _ = jax.tree_flatten(p1) - p2, _ = jax.tree_flatten(p2) + p1, _ = jax.tree.flatten(p1) + p2, _ = jax.tree.flatten(p2) diff = 0.0 for i in range(len(p1)): diff += np.sum((p1[i] - p2[i]) ** 2) From 4e4be08b2c7f6c3a47288846b47cd96c183c6e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 27 Feb 2024 16:33:52 +0100 Subject: [PATCH 043/192] bump jax version --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index de96f0d8..558ca426 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3476,4 +3476,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "ccf786de5155d696622984da7573282ff7f5e5062c9b386610145bf9fcb712b0" +content-hash = "644ac71059a5fb1c264908c3d41b1c05575697f1e3d13d0e8bec33b419db4ad0" diff --git a/pyproject.toml b/pyproject.toml index 5d4717e5..d62d4677 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ lazy-loader = "^0.2" matscipy = "^0.8.0" znh5md = "^0.1.7" pydantic = "^2.3.0" -jax = "^0.4.14" +jax = "^0.4.25" [tool.poetry.scripts] apax = 'apax.cli.apax_app:app' From 1d9e01ae28fd3f3300ba1f3b23d495e9f2228029 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:34:04 +0000 Subject: [PATCH 044/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/md/io.py | 2 +- apax/md/sim_utils.py | 1 + apax/model/gmnn.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apax/md/io.py b/apax/md/io.py index 2f1b0321..98ba8853 100644 --- a/apax/md/io.py +++ b/apax/md/io.py @@ -6,9 +6,9 @@ import znh5md from ase import Atoms from ase.calculators.singlepoint import SinglePointCalculator -from apax.utils.jax_md_reduced.space import transform from apax.md.sim_utils import System +from apax.utils.jax_md_reduced.space import transform log = logging.getLogger(__name__) diff --git a/apax/md/sim_utils.py b/apax/md/sim_utils.py index abcfcbe2..47ef6551 100644 --- a/apax/md/sim_utils.py +++ b/apax/md/sim_utils.py @@ -3,6 +3,7 @@ import jax.numpy as jnp import numpy as np + from apax.utils.jax_md_reduced.space import transform diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index 0b6d55e4..70c057fe 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -6,7 +6,7 @@ import jax import jax.numpy as jnp import numpy as np -from jax import vmap, Array +from jax import Array, vmap from apax.layers.descriptor.gaussian_moment_descriptor import GaussianMomentDescriptor from apax.layers.empirical import EmpiricalEnergyTerm From ba4272ca54bf2d28b1fe28456c10ca45c818fc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 28 Feb 2024 19:02:17 +0100 Subject: [PATCH 045/192] unified reduced jaxmd import path --- apax/data/preprocessing.py | 8 +++---- .../descriptor/gaussian_moment_descriptor.py | 4 ++-- apax/layers/empirical.py | 4 ++-- apax/md/ase_calc.py | 23 +++++++------------ apax/md/io.py | 4 ++-- apax/md/nvt.py | 11 ++++----- apax/md/sim_utils.py | 4 ++-- apax/train/trainer.py | 10 ++++---- apax/utils/convert.py | 4 ++-- apax/utils/jax_md_reduced/partition.py | 12 +++++----- apax/utils/jax_md_reduced/quantity.py | 10 ++++---- apax/utils/jax_md_reduced/space.py | 1 - 12 files changed, 45 insertions(+), 50 deletions(-) diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index fd1309a4..c3d65eaa 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -10,7 +10,7 @@ from matscipy.neighbours import neighbour_list from tqdm import trange -from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import partition, space log = logging.getLogger(__name__) @@ -21,14 +21,14 @@ def initialize_nbr_fn(atoms: Atoms, cutoff: float) -> Callable: box = jnp.asarray(atoms.cell.array) if np.all(box < 1e-6): - displacement_fn, _ = jax_md_reduced.space.free() + displacement_fn, _ = space.free() box = default_box - neighbor_fn = jax_md_reduced.partition.neighbor_list( + neighbor_fn = partition.neighbor_list( displacement_or_metric=displacement_fn, box=box, r_cutoff=cutoff, - format=jax_md_reduced.partition.Sparse, + format=partition.Sparse, fractional_coordinates=False, ) diff --git a/apax/layers/descriptor/gaussian_moment_descriptor.py b/apax/layers/descriptor/gaussian_moment_descriptor.py index 45dc2862..5fb1471d 100644 --- a/apax/layers/descriptor/gaussian_moment_descriptor.py +++ b/apax/layers/descriptor/gaussian_moment_descriptor.py @@ -9,7 +9,7 @@ from apax.layers.descriptor.moments import geometric_moments from apax.layers.descriptor.triangular_indices import tril_2d_indices, tril_3d_indices from apax.layers.masking import mask_by_neighbor -from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import space class GaussianMomentDescriptor(nn.Module): @@ -22,7 +22,7 @@ def setup(self): self.r_max = self.radial_fn.r_max self.n_radial = self.radial_fn._n_radial - self.distance = vmap(jax_md_reduced.space.distance, 0, 0) + self.distance = vmap(space.distance, 0, 0) self.triang_idxs_2d = tril_2d_indices(self.n_radial) self.triang_idxs_3d = tril_3d_indices(self.n_radial) diff --git a/apax/layers/empirical.py b/apax/layers/empirical.py index 896c8535..5adea3af 100644 --- a/apax/layers/empirical.py +++ b/apax/layers/empirical.py @@ -7,7 +7,7 @@ from jax import vmap from apax.layers.masking import mask_by_neighbor -from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import space from apax.utils.math import fp64_sum @@ -24,7 +24,7 @@ class ZBLRepulsion(EmpiricalEnergyTerm): apply_mask: bool = True def setup(self): - self.distance = vmap(jax_md_reduced.space.distance, 0, 0) + self.distance = vmap(space.distance, 0, 0) self.ke = 14.3996 diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 9ccd7baa..8b01bb3d 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -14,8 +14,7 @@ from apax.data.initialization import initialize_dataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters -from apax.utils import jax_md_reduced -from apax.utils.jax_md_reduced import quantity +from apax.utils.jax_md_reduced import partition, quantity, space def maybe_vmap(apply, params): @@ -40,20 +39,18 @@ def build_energy_neighbor_fns(atoms, config, params, dr_threshold, neigbor_from_ if neigbor_from_jax: if np.all(box < 1e-6): - displacement_fn, _ = jax_md_reduced.space.free() + displacement_fn, _ = space.free() else: - displacement_fn, _ = jax_md_reduced.space.periodic_general( - box, fractional_coordinates=True - ) + displacement_fn, _ = space.periodic_general(box, fractional_coordinates=True) - neighbor_fn = jax_md_reduced.partition.neighbor_list( + neighbor_fn = partition.neighbor_list( displacement_fn, box, config.model.r_max, dr_threshold, fractional_coordinates=True, disable_cell_list=True, - format=jax_md_reduced.partition.Sparse, + format=partition.Sparse, ) n_species = 119 # int(np.max(Z) + 1) @@ -171,9 +168,7 @@ def initialize(self, atoms): if np.any(atoms.get_cell().lengths() > 1e-6): box = atoms.cell.array.T inv_box = jnp.linalg.inv(box) - positions = jax_md_reduced.space.transform( - inv_box, positions - ) # frac coords + positions = space.transform(inv_box, positions) # frac coords self.neighbors = self.neighbor_fn.allocate(positions, box=box) else: self.neighbors = self.neighbor_fn.allocate(positions) @@ -228,9 +223,7 @@ def calculate(self, atoms, properties=["energy"], system_changes=all_changes): else: self.set_neighbours_and_offsets(atoms, box) - positions = np.array( - jax_md_reduced.space.transform(np.linalg.inv(box), atoms.positions) - ) + positions = np.array(space.transform(np.linalg.inv(box), atoms.positions)) results = self.step(positions, self.neighbors, box, self.offsets) @@ -331,7 +324,7 @@ def step_fn(positions, neighbor, box): if np.any(atoms.get_cell().lengths() > 1e-6): box = box.T inv_box = jnp.linalg.inv(box) - positions = jax_md_reduced.space.transform(inv_box, positions) + positions = space.transform(inv_box, positions) neighbor = neighbor.update(positions, box=box) else: neighbor = neighbor.update(positions) diff --git a/apax/md/io.py b/apax/md/io.py index 98ba8853..19b29c4b 100644 --- a/apax/md/io.py +++ b/apax/md/io.py @@ -8,7 +8,7 @@ from ase.calculators.singlepoint import SinglePointCalculator from apax.md.sim_utils import System -from apax.utils.jax_md_reduced.space import transform +from apax.utils.jax_md_reduced import space log = logging.getLogger(__name__) @@ -40,7 +40,7 @@ def atoms_from_state(self, state, energy, nbr_kwargs): box = self.box if self.fractional: - positions = transform(box, state.position) + positions = space.transform(box, state.position) else: positions = state.position diff --git a/apax/md/nvt.py b/apax/md/nvt.py index 7a16e452..6ee02196 100644 --- a/apax/md/nvt.py +++ b/apax/md/nvt.py @@ -23,8 +23,7 @@ restore_parameters, ) from apax.train.run import setup_logging -from apax.utils import jax_md_reduced -from apax.utils.jax_md_reduced import quantity, simulate +from apax.utils.jax_md_reduced import partition, quantity, simulate, space log = logging.getLogger(__name__) @@ -340,7 +339,7 @@ def md_setup(model_config: Config, md_config: MDConfig): r_max = model_config.model.r_max log.info("initializing model") if np.all(system.box < 1e-6): - displacement_fn, shift_fn = jax_md_reduced.space.free() + displacement_fn, shift_fn = space.free() else: heights = heights_of_box_sides(system.box) @@ -356,7 +355,7 @@ def md_setup(model_config: Config, md_config: MDConfig): f"one cell vector direction {heights/2} < {r_max}", "can not calculate the correct neighbors", ) - displacement_fn, shift_fn = jax_md_reduced.space.periodic_general( + displacement_fn, shift_fn = space.periodic_general( system.box, fractional_coordinates=True ) @@ -364,13 +363,13 @@ def md_setup(model_config: Config, md_config: MDConfig): model = builder.build_energy_model( apply_mask=True, init_box=np.array(system.box), inference_disp_fn=displacement_fn ) - neighbor_fn = jax_md_reduced.partition.neighbor_list( + neighbor_fn = partition.neighbor_list( displacement_fn, system.box, r_max, md_config.dr_threshold, fractional_coordinates=True, - format=jax_md_reduced.partition.Sparse, + format=partition.Sparse, disable_cell_list=True, ) diff --git a/apax/md/sim_utils.py b/apax/md/sim_utils.py index 47ef6551..85c250ac 100644 --- a/apax/md/sim_utils.py +++ b/apax/md/sim_utils.py @@ -4,7 +4,7 @@ import jax.numpy as jnp import numpy as np -from apax.utils.jax_md_reduced.space import transform +from apax.utils.jax_md_reduced import space @dataclasses.dataclass @@ -25,7 +25,7 @@ def from_atoms(cls, atoms): box = box.T positions = jnp.asarray(atoms.positions, dtype=jnp.float64) if np.any(box > 1e-6): - positions = transform(jnp.linalg.inv(box), positions) + positions = space.transform(jnp.linalg.inv(box), positions) system = cls( atomic_numbers=atomic_numbers, diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..684203eb 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,10 +109,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 9b66f08c..1b7aff03 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -5,7 +5,7 @@ from ase import Atoms from ase.units import Ang, Bohr, Hartree, eV, kcal, kJ, mol -from apax.utils import jax_md_reduced +from apax.utils.jax_md_reduced import space DTYPE = np.float64 unit_dict = { @@ -93,7 +93,7 @@ def atoms_to_inputs( inv_box = np.linalg.inv(box) inputs["ragged"]["positions"].append( np.array( - jax_md_reduced.space.transform( + space.transform( inv_box, (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) ) ) diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 35b3d3e5..36a7bafb 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -266,9 +266,9 @@ class NeighborList: format: NeighborListFormat = dataclasses.static_field() cell_size: Optional[float] = dataclasses.static_field() cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() - update_fn: Callable[[Array, "NeighborList"], "NeighborList"] = ( - dataclasses.static_field() - ) + update_fn: Callable[ + [Array, "NeighborList"], "NeighborList" + ] = dataclasses.static_field() def update(self, position: Array, **kwargs) -> "NeighborList": return self.update_fn(position, self, **kwargs) @@ -341,9 +341,9 @@ class NeighborList: format: NeighborListFormat = dataclasses.static_field() cell_size: Optional[float] = dataclasses.static_field() cell_list_fn: Callable[[Array, CellList], CellList] = dataclasses.static_field() - update_fn: Callable[[Array, "NeighborList"], "NeighborList"] = ( - dataclasses.static_field() - ) + update_fn: Callable[ + [Array, "NeighborList"], "NeighborList" + ] = dataclasses.static_field() def update(self, position: Array, **kwargs) -> "NeighborList": return self.update_fn(position, self, **kwargs) diff --git a/apax/utils/jax_md_reduced/quantity.py b/apax/utils/jax_md_reduced/quantity.py index c7434d07..b8dc47e7 100644 --- a/apax/utils/jax_md_reduced/quantity.py +++ b/apax/utils/jax_md_reduced/quantity.py @@ -328,10 +328,12 @@ def average_pair_correlation_results(gofr, species=None): if species is None: return jnp.mean(gofr, axis=0) species_types = jnp.unique(species) # note: this returns in sorted order - return jnp.array([ - [jnp.mean(gofr[si][species == s], axis=0) for s in species_types] - for si in range(species_types.size) - ]) + return jnp.array( + [ + [jnp.mean(gofr[si][species == s], axis=0) for s in species_types] + for si in range(species_types.size) + ] + ) def pair_correlation( diff --git a/apax/utils/jax_md_reduced/space.py b/apax/utils/jax_md_reduced/space.py index 4d757aed..40d7cc02 100644 --- a/apax/utils/jax_md_reduced/space.py +++ b/apax/utils/jax_md_reduced/space.py @@ -16,7 +16,6 @@ import jax.numpy as jnp from jax import custom_jvp, vmap -# from jax_md import space from apax.utils.jax_md_reduced.util import Array, f32, f64, safe_mask From 57ae55d2482f3486d8a78a75191bc1c9e8bb00dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 18:02:28 +0000 Subject: [PATCH 046/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 684203eb..0c96277b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -109,12 +109,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From b6eda9be54ce83ca29f147b168c6dce7ad3ce5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 12:43:16 +0100 Subject: [PATCH 047/192] added nblink dependencies --- poetry.lock | 678 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 + 2 files changed, 679 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 558ca426..613f5b7b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -84,6 +84,25 @@ files = [ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + [[package]] name = "babel" version = "2.14.0" @@ -153,6 +172,24 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "bleach" +version = "6.1.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.8" +files = [ + {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, + {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.3)"] + [[package]] name = "cached-property" version = "1.5.2" @@ -186,6 +223,70 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "cfgv" version = "3.4.0" @@ -554,6 +655,17 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "distlib" version = "0.3.8" @@ -701,6 +813,20 @@ files = [ [package.extras] testing = ["hatch", "pre-commit", "pytest", "tox"] +[[package]] +name = "fastjsonschema" +version = "2.19.1" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +files = [ + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + [[package]] name = "filelock" version = "3.13.1" @@ -1258,6 +1384,94 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jsonschema" +version = "4.21.1" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, + {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "jupyter-client" +version = "8.6.0" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, + {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, +] + +[package.dependencies] +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-core" +version = "5.7.1" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, + {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +description = "Pygments theme using JupyterLab CSS variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, + {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, +] + [[package]] name = "keras" version = "2.15.0" @@ -1664,6 +1878,17 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "mistune" +version = "3.0.2" +description = "A sane and fast Markdown parser with useful plugins and renderers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, + {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, +] + [[package]] name = "ml-collections" version = "0.1.1" @@ -1817,6 +2042,120 @@ rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4. testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] +[[package]] +name = "nbclient" +version = "0.9.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "nbclient-0.9.0-py3-none-any.whl", hash = "sha256:a3a1ddfb34d4a9d17fc744d655962714a866639acd30130e9be84191cd97cd15"}, + {file = "nbclient-0.9.0.tar.gz", hash = "sha256:4b28c207877cf33ef3a9838cdc7a54c5ceff981194a82eac59d558f05487295e"}, +] + +[package.dependencies] +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +nbformat = ">=5.1" +traitlets = ">=5.4" + +[package.extras] +dev = ["pre-commit"] +docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.16.1" +description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbconvert-7.16.1-py3-none-any.whl", hash = "sha256:3188727dffadfdc9c6a1c7250729063d7bc78b355ad7aa023138afa030d1cd07"}, + {file = "nbconvert-7.16.1.tar.gz", hash = "sha256:e79e6a074f49ba3ed29428ed86487bf51509d9aab613bd8522ac08f6d28fd7fd"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "!=5.0.0" +defusedxml = "*" +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<4" +nbclient = ">=0.5.0" +nbformat = ">=5.7" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.1" + +[package.extras] +all = ["nbconvert[docs,qtpdf,serve,test,webpdf]"] +docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +qtpdf = ["nbconvert[qtpng]"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest"] +webpdf = ["playwright"] + +[[package]] +name = "nbformat" +version = "5.9.2" +description = "The Jupyter Notebook format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"}, + {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"}, +] + +[package.dependencies] +fastjsonschema = "*" +jsonschema = ">=2.6" +jupyter-core = "*" +traitlets = ">=5.1" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "nbsphinx" +version = "0.9.3" +description = "Jupyter Notebook Tools for Sphinx" +optional = false +python-versions = ">=3.6" +files = [ + {file = "nbsphinx-0.9.3-py3-none-any.whl", hash = "sha256:6e805e9627f4a358bd5720d5cbf8bf48853989c79af557afd91a5f22e163029f"}, + {file = "nbsphinx-0.9.3.tar.gz", hash = "sha256:ec339c8691b688f8676104a367a4b8cf3ea01fd089dc28d24dec22d563b11562"}, +] + +[package.dependencies] +docutils = "*" +jinja2 = "*" +nbconvert = "!=5.4" +nbformat = "*" +sphinx = ">=1.8" +traitlets = ">=5" + +[[package]] +name = "nbsphinx-link" +version = "1.3.0" +description = "A sphinx extension for including notebook files outside sphinx source root" +optional = false +python-versions = "*" +files = [ + {file = "nbsphinx-link-1.3.0.tar.gz", hash = "sha256:fa3079a74c0dff1b2079e79a34babe770706ba8aa9cc0609c6dbfd593461a077"}, + {file = "nbsphinx_link-1.3.0-py2.py3-none-any.whl", hash = "sha256:67c24fc6508765203afb4b6939c0d9127e17a5d8d9355bfe8458192cf7105eb9"}, +] + +[package.dependencies] +nbsphinx = "*" +sphinx = ">=1.8" + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -1983,6 +2322,17 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pandocfilters" +version = "1.5.1" +description = "Utilities for writing pandoc filters in python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, +] + [[package]] name = "pathspec" version = "0.12.1" @@ -2238,6 +2588,17 @@ files = [ {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + [[package]] name = "pydantic" version = "2.6.2" @@ -2462,6 +2823,29 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -2511,6 +2895,126 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "pyzmq" +version = "25.1.2" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4"}, + {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08"}, + {file = "pyzmq-25.1.2-cp310-cp310-win32.whl", hash = "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886"}, + {file = "pyzmq-25.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6"}, + {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c"}, + {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3"}, + {file = "pyzmq-25.1.2-cp311-cp311-win32.whl", hash = "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097"}, + {file = "pyzmq-25.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9"}, + {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a"}, + {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737"}, + {file = "pyzmq-25.1.2-cp312-cp312-win32.whl", hash = "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d"}, + {file = "pyzmq-25.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7"}, + {file = "pyzmq-25.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16"}, + {file = "pyzmq-25.1.2-cp36-cp36m-win32.whl", hash = "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc"}, + {file = "pyzmq-25.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68"}, + {file = "pyzmq-25.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b"}, + {file = "pyzmq-25.1.2-cp37-cp37m-win32.whl", hash = "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7"}, + {file = "pyzmq-25.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd"}, + {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41"}, + {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755"}, + {file = "pyzmq-25.1.2-cp38-cp38-win32.whl", hash = "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07"}, + {file = "pyzmq-25.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088"}, + {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6"}, + {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2"}, + {file = "pyzmq-25.1.2-cp39-cp39-win32.whl", hash = "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289"}, + {file = "pyzmq-25.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314"}, + {file = "pyzmq-25.1.2.tar.gz", hash = "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "referencing" +version = "0.33.0" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, + {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "requests" version = "2.31.0" @@ -2568,6 +3072,114 @@ pygments = ">=2.6.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] +[[package]] +name = "rpds-py" +version = "0.18.0" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, + {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, + {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, + {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, + {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, + {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, + {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, + {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, + {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, + {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, + {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, + {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, + {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, +] + [[package]] name = "rsa" version = "4.9" @@ -3194,6 +3806,24 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] +[[package]] +name = "tinycss2" +version = "1.2.1" +description = "A tiny CSS parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, + {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + [[package]] name = "toml" version = "0.10.2" @@ -3227,6 +3857,26 @@ files = [ {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, ] +[[package]] +name = "tornado" +version = "6.4" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, + {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, + {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, + {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, + {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, +] + [[package]] name = "tqdm" version = "4.66.2" @@ -3247,6 +3897,21 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "traitlets" +version = "5.14.1" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] + [[package]] name = "typeguard" version = "2.13.3" @@ -3333,6 +3998,17 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + [[package]] name = "werkzeug" version = "3.0.1" @@ -3476,4 +4152,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "644ac71059a5fb1c264908c3d41b1c05575697f1e3d13d0e8bec33b419db4ad0" +content-hash = "4d5cd274eb1c44b3b50b88e88857f820268bf353ec117f006265b403fec1b001" diff --git a/pyproject.toml b/pyproject.toml index d62d4677..ea28db66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,8 @@ matplotlib = "^3.6.2" pre-commit = "^2.20.0" isort = "^5.10.1" flake8 = "^5.0.4" +nbsphinx = "^0.9.3" +nbsphinx-link = "^1.3.0" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" From 6cf4f9aab0a47583d3391c0d6c856d85cccf8508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 12:43:35 +0100 Subject: [PATCH 048/192] updated example index --- docs/source/_tutorials/index.rst | 6 +++--- docs/source/conf.py | 3 +++ ...3_Transfer_learning.ipynb => 03_Transfer_Learning.ipynb} | 0 3 files changed, 6 insertions(+), 3 deletions(-) rename examples/{03_Transfer_learning.ipynb => 03_Transfer_Learning.ipynb} (100%) diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index 8df2115c..e91c16a4 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -5,6 +5,6 @@ Tutorials :maxdepth: 2 01_Model_Training - md_with_ase - molecular_dynamics - transfer_learning + 02_Molecular_dynamics + 03_Transfer_Learning + 04_Batch_Data_Selection diff --git a/docs/source/conf.py b/docs/source/conf.py index 76d09acd..da514999 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,6 +26,9 @@ "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.mathjax", + "nbsphinx", + "nbsphinx_link", + "sphinx.ext.viewcode", ] templates_path = ["_templates"] diff --git a/examples/03_Transfer_learning.ipynb b/examples/03_Transfer_Learning.ipynb similarity index 100% rename from examples/03_Transfer_learning.ipynb rename to examples/03_Transfer_Learning.ipynb From 99ec9259db2c206213cc1163d719c9c890b9fb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 13:12:23 +0100 Subject: [PATCH 049/192] fixed docstring formatting --- apax/bal/api.py | 14 ++++++------ apax/config/md_config.py | 47 +++++++++++++++++++++++++-------------- apax/layers/properties.py | 18 ++++++++++----- apax/model/gmnn.py | 10 ++++++++- apax/utils/data.py | 36 +++++++++++++++++------------- 5 files changed, 78 insertions(+), 47 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index 97013f77..34a32467 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -43,9 +43,6 @@ def create_feature_fn( Model parameters base_feature_map: FeatureTransformation Class that transforms the model into a `FeatureMap` - feature_transforms: list - Feature tranforms to be applied on top of the base feature map transform. - Examples would include multiplcation with or addition of a constant. is_ensemble: bool Whether or not to apply the ensemble transformation i.e. an averaging of kernels for model ensembles. """ @@ -68,9 +65,9 @@ def compute_features(feature_fn: feature_maps.FeatureMap, dataset: AtomisticData Attributes ---------- - feature_fn: FeatureMap + feature_fn: Function to compute the features with. - dataset: AtomisticDataset + dataset: Dataset to compute the features for. """ features = [] @@ -99,7 +96,7 @@ def kernel_selection( processing_batch_size: int = 64, ) -> list[int]: """ - Main fuinction to facilitate batch data selection. + Main function to facilitate batch data selection. Currently only the last layer gradient features and MaxDist selection method are available. More can be added as needed as this function is agnostic of the feature map/selection method internals. @@ -112,9 +109,12 @@ def kernel_selection( pool_atoms: List[Atoms] List of `ase.Atoms` to select new data from. base_fm_options: - Dict + Settings for the base feature map. selection_method: + Currently only "max_dist" is supported. feature_transforms: + Feature tranforms to be applied on top of the base feature map transform. + Examples would include multiplcation with or addition of a constant. selection_batch_size: Amount of new data points to be selected from `pool_atoms`. processing_batch_size: diff --git a/apax/config/md_config.py b/apax/config/md_config.py index a8321e29..f34a1889 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -35,33 +35,46 @@ class NPTOptions(NVTOptions, extra="forbid"): class MDConfig(BaseModel, frozen=True, extra="forbid"): - """ - Configuration for a NHC molecular dynamics simulation. - - Parameters: - seed: Random seed for momentum initialization. - temperature: Temperature of the simulation in Kelvin. - dt: Time step in fs. - duration: Total simulation time in fs. - n_inner: Number of compiled simulation steps (i.e. number of iterations of the + """Configuration for a NHC molecular dynamics simulation. + + Attributes + ---------- + seed: + Random seed for momentum initialization. + temperature: + Temperature of the simulation in Kelvin. + dt: + Time step in fs. + duration: + Total simulation time in fs. + n_inner: + Number of compiled simulation steps (i.e. number of iterations of the `jax.lax.fori_loop` loop). Also determines atoms buffer size. sampling_rate: Interval between saving frames. buffer_size: Number of collected frames to be dumped at once. - dr_threshold: Skin of the neighborlist. - extra_capacity: JaxMD allocates a maximal number of neighbors. + dr_threshold: + Skin of the neighborlist. + extra_capacity: + JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. - intitial_structure: Path to the starting structure of the simulation. - sim_dir: Directory where simulation file will be stored. - traj_name: Name of the trajectory file. - restart: Whether the simulation should restart from the latest configuration + intitial_structure: + Path to the starting structure of the simulation. + sim_dir: + Directory where simulation file will be stored. + traj_name: + Name of the trajectory file. + restart: + Whether the simulation should restart from the latest configuration in `traj_name`. - checkpoint_interval: Number of time steps between saving + checkpoint_interval: + Number of time steps between saving full simulation state checkpoints. These will be loaded with the `restart` option. - disable_pbar: Disables the MD progressbar. + disable_pbar: + Disables the MD progressbar. """ seed: int = 1 diff --git a/apax/layers/properties.py b/apax/layers/properties.py index 8889314c..e80cd36d 100644 --- a/apax/layers/properties.py +++ b/apax/layers/properties.py @@ -7,17 +7,23 @@ def stress_times_vol(energy_fn, position: Array, box, **kwargs) -> Array: """Computes the internal stress of a system multiplied with the box volume. For training purposes. - Args: - energy_fn: A function that computes the energy of the system. This + Parameters + ---------- + energy_fn: + A function that computes the energy of the system. This function must take as an argument `perturbation` which perturbs the box shape. Any energy function constructed using `smap` or in `energy.py` with a standard space will satisfy this property. - position: An array of particle positions. - box: A box specifying the shape of the simulation volume. Used to infer the + position: + An array of particle positions. + box: + A box specifying the shape of the simulation volume. Used to infer the volume of the unit cell. - Returns: - A float specifying the stress of the system. + Returns + ------- + Array + A float specifying the stress of the system. """ dim = position.shape[1] zero = jnp.zeros((dim, dim), position.dtype) diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index 70c057fe..d645f9fa 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -48,6 +48,9 @@ def disp_fn(ri, rj, perturbation, box): class AtomisticModel(nn.Module): + """Most basic prediction model. + Allesmbles descriptor, readout (NNs) and output scale-shifting. + """ descriptor: nn.Module = GaussianMomentDescriptor() readout: nn.Module = AtomisticReadout() scale_shift: nn.Module = PerElementScaleShift() @@ -69,6 +72,9 @@ def __call__( class EnergyModel(nn.Module): + """Model which post processes the output of an atomistic model and + adds empirical energy terms. + """ atomistic_model: AtomisticModel = AtomisticModel() corrections: list[EmpiricalEnergyTerm] = field(default_factory=lambda: []) init_box: np.array = field(default_factory=lambda: np.array([0.0, 0.0, 0.0])) @@ -128,9 +134,11 @@ def __call__( class EnergyDerivativeModel(nn.Module): + """Transforms an EnergyModel into one that also predicts derivatives the total energy. + Can calculate forces and stress tensors. + """ # Alternatively, should this be a function transformation? energy_model: EnergyModel = EnergyModel() - corrections: list[EmpiricalEnergyTerm] = field(default_factory=lambda: []) calc_stress: bool = False def __call__( diff --git a/apax/utils/data.py b/apax/utils/data.py index 559f0975..e7619fa4 100644 --- a/apax/utils/data.py +++ b/apax/utils/data.py @@ -22,31 +22,35 @@ def make_minimal_input(): def load_data(data_path): """Non ASE compatible parameters have to be saved in an exta file that has the same name as the datapath but with the extension `_labels.npz`. - example for the npz-file: - - dipole = np.random.rand(3, 1) - charge = np.random.rand(3, 2) - mat = np.random.rand(3, 1) - shape = ['ragged', 'ragged', 'fixed'] - - np.savez( - "data_path_labels.npz", - dipole=dipole, - charge=charge, - mat=mat, - shape=shape, - ) + + Example + ------- + example for the npz-file:: + + + dipole = np.random.rand(3, 1) + charge = np.random.rand(3, 2) + mat = np.random.rand(3, 1) + shape = ['ragged', 'ragged', 'fixed'] + + np.savez( + "data_path_labels.npz", + dipole=dipole, + charge=charge, + mat=mat, + shape=shape, + ) shape has to be in the same order than the parameters Parameters ---------- - data_path : + data_path: Path to the ASE readable file that includes all structures. Returns ------- - atoms_list + list List of all structures where entries are ASE atoms objects. """ From e49909af0f4223f01a754a2db5e2f247ad3c2ac6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:12:40 +0000 Subject: [PATCH 050/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/_tutorials/01_Model_Training.nblink | 2 +- docs/source/_tutorials/02_Molecular_dynamics.nblink | 2 +- docs/source/_tutorials/03_Transfer_Learning.nblink | 2 +- docs/source/_tutorials/04_Batch_Data_Selection.nblink | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/_tutorials/01_Model_Training.nblink b/docs/source/_tutorials/01_Model_Training.nblink index ff4c4579..0bfa2785 100644 --- a/docs/source/_tutorials/01_Model_Training.nblink +++ b/docs/source/_tutorials/01_Model_Training.nblink @@ -1,3 +1,3 @@ { "path": "../../../examples/01_Model_Training.ipynb" -} \ No newline at end of file +} diff --git a/docs/source/_tutorials/02_Molecular_dynamics.nblink b/docs/source/_tutorials/02_Molecular_dynamics.nblink index 4dfadfe9..de498161 100644 --- a/docs/source/_tutorials/02_Molecular_dynamics.nblink +++ b/docs/source/_tutorials/02_Molecular_dynamics.nblink @@ -1,3 +1,3 @@ { "path": "../../../examples/02_Molecular_Dynamics.ipynb" -} \ No newline at end of file +} diff --git a/docs/source/_tutorials/03_Transfer_Learning.nblink b/docs/source/_tutorials/03_Transfer_Learning.nblink index 27f929dc..0dd837aa 100644 --- a/docs/source/_tutorials/03_Transfer_Learning.nblink +++ b/docs/source/_tutorials/03_Transfer_Learning.nblink @@ -1,3 +1,3 @@ { "path": "../../../examples/03_Transfer_Learning.ipynb" -} \ No newline at end of file +} diff --git a/docs/source/_tutorials/04_Batch_Data_Selection.nblink b/docs/source/_tutorials/04_Batch_Data_Selection.nblink index dbd195e4..f6debea5 100644 --- a/docs/source/_tutorials/04_Batch_Data_Selection.nblink +++ b/docs/source/_tutorials/04_Batch_Data_Selection.nblink @@ -1,3 +1,3 @@ { "path": "../../../examples/04_Batch_Data_Selection.ipynb" -} \ No newline at end of file +} From 2c65ac90538f209d5e5570fe633a52ce8fcfa8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:06:03 +0100 Subject: [PATCH 051/192] removed unused corrections parameter in energyderivativemodel --- apax/model/builder.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apax/model/builder.py b/apax/model/builder.py index 71a079b4..09e1972c 100644 --- a/apax/model/builder.py +++ b/apax/model/builder.py @@ -121,17 +121,9 @@ def build_energy_derivative_model( init_box=init_box, inference_disp_fn=inference_disp_fn, ) - corrections = [] - if self.config["use_zbl"]: - repulsion = ZBLRepulsion( - apply_mask=apply_mask, - r_max=self.config["r_max"], - ) - corrections.append(repulsion) model = EnergyDerivativeModel( energy_model, - corrections=corrections, calc_stress=self.config["calc_stress"], ) return model From d5fd3223aba17228d6e9023360f62bfb3549452d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:06:40 +0000 Subject: [PATCH 052/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/bal/api.py | 2 +- apax/bal/feature_maps.py | 6 +++--- apax/utils/data.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index 34a32467..3bfb1099 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -62,7 +62,7 @@ def create_feature_fn( def compute_features(feature_fn: feature_maps.FeatureMap, dataset: AtomisticDataset) -> np.ndarray: """Compute the features of a dataset. - + Attributes ---------- feature_fn: diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index 264b0436..8bfec317 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -13,7 +13,7 @@ class FeatureTransformation(BaseModel): - def apply(self, model: EnergyModel) -> FeatureMap: + def apply(self, model: EnergyModel) -> FeatureMap: ... @@ -43,7 +43,7 @@ class LastLayerGradientFeatures(FeatureTransformation, extra="forbid"): name: Literal["ll_grad"] layer_name: str = "dense_2" - def apply(self, model: EnergyModel) -> FeatureMap: + def apply(self, model: EnergyModel) -> FeatureMap: def ll_grad(params, inputs): ll_params, remaining_params = extract_feature_params(params, self.layer_name) @@ -83,7 +83,7 @@ class IdentityFeatures(FeatureTransformation, extra="forbid"): name: Literal["identity"] - def apply(self, model: EnergyModel) -> FeatureMap: + def apply(self, model: EnergyModel) -> FeatureMap: return model.apply diff --git a/apax/utils/data.py b/apax/utils/data.py index e7619fa4..057f0718 100644 --- a/apax/utils/data.py +++ b/apax/utils/data.py @@ -22,12 +22,12 @@ def make_minimal_input(): def load_data(data_path): """Non ASE compatible parameters have to be saved in an exta file that has the same name as the datapath but with the extension `_labels.npz`. - + Example ------- example for the npz-file:: - + dipole = np.random.rand(3, 1) charge = np.random.rand(3, 2) mat = np.random.rand(3, 1) From 8d5d918ae70e142d53dd72c546b450778357a4bc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:07:42 +0000 Subject: [PATCH 053/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/bal/api.py | 4 +++- apax/bal/feature_maps.py | 4 ++-- apax/model/gmnn.py | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index 3bfb1099..e9d2fdfd 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -60,7 +60,9 @@ def create_feature_fn( return feature_fn -def compute_features(feature_fn: feature_maps.FeatureMap, dataset: AtomisticDataset) -> np.ndarray: +def compute_features( + feature_fn: feature_maps.FeatureMap, dataset: AtomisticDataset +) -> np.ndarray: """Compute the features of a dataset. Attributes diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index 8bfec317..5805dfd1 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -11,10 +11,10 @@ FeatureMap = Callable[[FrozenDict, dict], jax.Array] + class FeatureTransformation(BaseModel): - def apply(self, model: EnergyModel) -> FeatureMap: - ... + def apply(self, model: EnergyModel) -> FeatureMap: ... def extract_feature_params(params: dict, layer_name: str) -> Tuple[dict, dict]: diff --git a/apax/model/gmnn.py b/apax/model/gmnn.py index d645f9fa..73aa8da0 100644 --- a/apax/model/gmnn.py +++ b/apax/model/gmnn.py @@ -51,6 +51,7 @@ class AtomisticModel(nn.Module): """Most basic prediction model. Allesmbles descriptor, readout (NNs) and output scale-shifting. """ + descriptor: nn.Module = GaussianMomentDescriptor() readout: nn.Module = AtomisticReadout() scale_shift: nn.Module = PerElementScaleShift() @@ -75,6 +76,7 @@ class EnergyModel(nn.Module): """Model which post processes the output of an atomistic model and adds empirical energy terms. """ + atomistic_model: AtomisticModel = AtomisticModel() corrections: list[EmpiricalEnergyTerm] = field(default_factory=lambda: []) init_box: np.array = field(default_factory=lambda: np.array([0.0, 0.0, 0.0])) @@ -137,6 +139,7 @@ class EnergyDerivativeModel(nn.Module): """Transforms an EnergyModel into one that also predicts derivatives the total energy. Can calculate forces and stress tensors. """ + # Alternatively, should this be a function transformation? energy_model: EnergyModel = EnergyModel() calc_stress: bool = False From 62978b696532e862e5bd92099b7ac5d8ad59b08d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:08:14 +0000 Subject: [PATCH 054/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/bal/api.py | 2 +- apax/bal/feature_maps.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index e9d2fdfd..dbbc7ff4 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -5,8 +5,8 @@ import numpy as np from ase import Atoms from click import Path -from tqdm import trange from flax.core.frozen_dict import FrozenDict +from tqdm import trange from apax.bal import feature_maps, kernel, selection, transforms from apax.data.input_pipeline import AtomisticDataset diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index 5805dfd1..b287e0d1 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -2,12 +2,11 @@ import jax import jax.numpy as jnp +from flax.core.frozen_dict import FrozenDict from flax.traverse_util import flatten_dict, unflatten_dict from pydantic import BaseModel, TypeAdapter from apax.model.gmnn import EnergyModel -from flax.core.frozen_dict import FrozenDict - FeatureMap = Callable[[FrozenDict, dict], jax.Array] From 1e7d37e78fdc71d32f8592eb873d187317545492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:10:47 +0100 Subject: [PATCH 055/192] api --- apax/bal/api.py | 12 ++++++++---- apax/bal/feature_maps.py | 3 ++- apax/md/ase_calc.py | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index dbbc7ff4..c6da7602 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -44,7 +44,8 @@ def create_feature_fn( base_feature_map: FeatureTransformation Class that transforms the model into a `FeatureMap` is_ensemble: bool - Whether or not to apply the ensemble transformation i.e. an averaging of kernels for model ensembles. + Whether or not to apply the ensemble transformation i.e. + an averaging of kernels for model ensembles. """ feature_fn = base_feature_map.apply(model) @@ -99,8 +100,10 @@ def kernel_selection( ) -> list[int]: """ Main function to facilitate batch data selection. - Currently only the last layer gradient features and MaxDist selection method are available. - More can be added as needed as this function is agnostic of the feature map/selection method internals. + Currently only the last layer gradient features and MaxDist selection method + are available. + More can be added as needed as this function is agnostic of the feature + map/selection method internals. Attributes ---------- @@ -115,7 +118,8 @@ def kernel_selection( selection_method: Currently only "max_dist" is supported. feature_transforms: - Feature tranforms to be applied on top of the base feature map transform. + Feature tranforms to be applied on top of the + base feature map transform. Examples would include multiplcation with or addition of a constant. selection_batch_size: Amount of new data points to be selected from `pool_atoms`. diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index b287e0d1..66223af8 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -13,7 +13,8 @@ class FeatureTransformation(BaseModel): - def apply(self, model: EnergyModel) -> FeatureMap: ... + def apply(self, model: EnergyModel) -> FeatureMap: + return model def extract_feature_params(params: dict, layer_name: str) -> Tuple[dict, dict]: diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 34ce9088..4d5780f9 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -126,7 +126,8 @@ def __init__( Parameters ---------- model_dir: - Path to a model directory of the form `.../directory/experiment` (see Config docs for details). + Path to a model directory of the form `.../directory/experiment` + (see Config docs for details). If a list of model paths is provided, they will be ensembled. dr_threshold: Neighborlist skin for the JaxMD neighborlist. @@ -135,7 +136,8 @@ def __init__( Transfomrations are implemented under `apax.md.transformations`. padding_factor: Multiple of the fallback Matscipy NL's amount of neighbors. - This NL will be padded to `len(neighbors) * padding_factor` on NL initialization. + This NL will be padded to `len(neighbors) * padding_factor` + on NL initialization. """ Calculator.__init__(self, **kwargs) self.dr_threshold = dr_threshold From f29604d12e632d030ee2db029adbdfad8dd3af92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:13:58 +0100 Subject: [PATCH 056/192] added ipykernel to env for doc building --- poetry.lock | 304 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 304 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 613f5b7b..cc532208 100644 --- a/poetry.lock +++ b/poetry.lock @@ -33,6 +33,17 @@ files = [ {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + [[package]] name = "array-record" version = "0.5.0" @@ -69,6 +80,24 @@ scipy = ">=1.1.0" docs = ["pillow", "sphinx", "sphinx-rtd-theme"] test = ["pytest (>=5.0.0)", "pytest-mock (>=3.3.0)", "pytest-xdist (>=1.30.0)"] +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + [[package]] name = "astunparse" version = "1.6.3" @@ -487,6 +516,23 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "comm" +version = "0.2.1" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.8" +files = [ + {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, + {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +test = ["pytest"] + [[package]] name = "commonmark" version = "0.9.1" @@ -655,6 +701,48 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "debugpy" +version = "1.8.1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, + {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, + {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, + {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, + {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, + {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, + {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, + {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, + {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, + {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, + {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, + {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, + {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, + {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, + {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, + {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, + {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, + {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, + {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, + {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, + {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, + {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + [[package]] name = "defusedxml" version = "0.7.1" @@ -813,6 +901,20 @@ files = [ [package.extras] testing = ["hatch", "pre-commit", "pytest", "tox"] +[[package]] +name = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + [[package]] name = "fastjsonschema" version = "2.19.1" @@ -1265,6 +1367,75 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "ipykernel" +version = "6.29.3" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.29.3-py3-none-any.whl", hash = "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21"}, + {file = "ipykernel-6.29.3.tar.gz", hash = "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=24" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.22.1" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "ipython-8.22.1-py3-none-any.whl", hash = "sha256:869335e8cded62ffb6fac8928e5287a05433d6462e3ebaac25f4216474dd6bc4"}, + {file = "ipython-8.22.1.tar.gz", hash = "sha256:39c6f9efc079fb19bfb0f17eee903978fe9a290b1b82d68196c641cecb76ea22"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt-toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5.13.0" + +[package.extras] +all = ["ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + [[package]] name = "isort" version = "5.13.2" @@ -1367,6 +1538,25 @@ numpy = ">=1.20.0" typeguard = ">=2.13.3,<3" typing-extensions = ">=3.7.4.1" +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + [[package]] name = "jinja2" version = "3.1.3" @@ -1798,6 +1988,20 @@ pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + [[package]] name = "matscipy" version = "0.8.1" @@ -2333,6 +2537,21 @@ files = [ {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, ] +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + [[package]] name = "pathspec" version = "0.12.1" @@ -2344,6 +2563,20 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + [[package]] name = "pillow" version = "10.2.0" @@ -2493,6 +2726,20 @@ six = "*" [package.extras] test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", "pytest-cov"] +[[package]] +name = "prompt-toolkit" +version = "3.0.43" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, +] + +[package.dependencies] +wcwidth = "*" + [[package]] name = "protobuf" version = "3.20.3" @@ -2552,6 +2799,31 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "pyasn1" version = "0.5.1" @@ -3511,6 +3783,25 @@ lint = ["docutils-stubs", "flake8", "mypy"] standalone = ["Sphinx (>=5)"] test = ["pytest"] +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + [[package]] name = "tensorboard" version = "2.15.2" @@ -3998,6 +4289,17 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [[package]] name = "webencodings" version = "0.5.1" @@ -4152,4 +4454,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "4d5cd274eb1c44b3b50b88e88857f820268bf353ec117f006265b403fec1b001" +content-hash = "3836dccf9cba978f753ae2c7c2cd4b087e2e62b515b739cf8da1acc946658e82" diff --git a/pyproject.toml b/pyproject.toml index ea28db66..e5c96b69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ isort = "^5.10.1" flake8 = "^5.0.4" nbsphinx = "^0.9.3" nbsphinx-link = "^1.3.0" +ipykernel = "^6.29.3" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" From 86494d42ba2b391a176bbf653b1c2d8795af36be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:18:26 +0100 Subject: [PATCH 057/192] added pandoc dependency --- poetry.lock | 46 +++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index cc532208..79ccfb30 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2526,6 +2526,20 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pandoc" +version = "2.3" +description = "Pandoc Documents for Python" +optional = false +python-versions = "*" +files = [ + {file = "pandoc-2.3.tar.gz", hash = "sha256:e772c2c6d871146894579828dbaf1efd538eb64fc7e71d4a6b3a11a18baef90d"}, +] + +[package.dependencies] +plumbum = "*" +ply = "*" + [[package]] name = "pandocfilters" version = "1.5.1" @@ -2692,6 +2706,36 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "plumbum" +version = "1.8.2" +description = "Plumbum: shell combinators library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "plumbum-1.8.2-py3-none-any.whl", hash = "sha256:3ad9e5f56c6ec98f6f7988f7ea8b52159662ea9e915868d369dbccbfca0e367e"}, + {file = "plumbum-1.8.2.tar.gz", hash = "sha256:9e6dc032f4af952665f32f3206567bc23b7858b1413611afe603a3f8ad9bfd75"}, +] + +[package.dependencies] +pywin32 = {version = "*", markers = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\""} + +[package.extras] +dev = ["paramiko", "psutil", "pytest (>=6.0)", "pytest-cov", "pytest-mock", "pytest-timeout"] +docs = ["sphinx (>=4.0.0)", "sphinx-rtd-theme (>=1.0.0)"] +ssh = ["paramiko"] + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + [[package]] name = "pre-commit" version = "2.21.0" @@ -4454,4 +4498,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "3836dccf9cba978f753ae2c7c2cd4b087e2e62b515b739cf8da1acc946658e82" +content-hash = "af4808dda7ba665f6b23043afaeb897c7323bbcc41a928d67db94dc4612cc85e" diff --git a/pyproject.toml b/pyproject.toml index e5c96b69..32107fdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ flake8 = "^5.0.4" nbsphinx = "^0.9.3" nbsphinx-link = "^1.3.0" ipykernel = "^6.29.3" +pandoc = "^2.3" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" From 4058580dbe82a96988d15cee9a054deaf51c44b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:26:48 +0100 Subject: [PATCH 058/192] bumped autodoc typehints --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 79ccfb30..cbeb64e4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3648,13 +3648,13 @@ test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools [[package]] name = "sphinx-autodoc-typehints" -version = "1.25.3" +version = "2.0.0" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.8" files = [ - {file = "sphinx_autodoc_typehints-1.25.3-py3-none-any.whl", hash = "sha256:d3da7fa9a9761eff6ff09f8b1956ae3090a2d4f4ad54aebcade8e458d6340835"}, - {file = "sphinx_autodoc_typehints-1.25.3.tar.gz", hash = "sha256:70db10b391acf4e772019765991d2de0ff30ec0899b9ba137706dc0b3c4835e0"}, + {file = "sphinx_autodoc_typehints-2.0.0-py3-none-any.whl", hash = "sha256:12c0e161f6fe191c2cdfd8fa3caea271f5387d9fbc67ebcd6f4f1f24ce880993"}, + {file = "sphinx_autodoc_typehints-2.0.0.tar.gz", hash = "sha256:7f2cdac2e70fd9787926b6e9e541cd4ded1e838d2b46fda2a1bb0a75ec5b7f3a"}, ] [package.dependencies] @@ -4498,4 +4498,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "af4808dda7ba665f6b23043afaeb897c7323bbcc41a928d67db94dc4612cc85e" +content-hash = "f278d560dc4fc1546894537db9ec71d02379e610fe7078b085ba8f14d976ddc3" diff --git a/pyproject.toml b/pyproject.toml index 32107fdd..b85a93b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,13 +43,13 @@ nbsphinx = "^0.9.3" nbsphinx-link = "^1.3.0" ipykernel = "^6.29.3" pandoc = "^2.3" +sphinx-autodoc-typehints = "^2.0.0" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" sphinx-rtd-theme = "^1.3.0" myst-parser = "^2.0.0" sphinx-copybutton = "^0.5.2" -sphinx-autodoc-typehints = "^1.25.2" furo = "^2023.9.10" [build-system] From 6cd379c7a6f21a571ccb9a72f845ab757ed604b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:28:13 +0100 Subject: [PATCH 059/192] rtd install with dev --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1302af38..4ce2983a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,7 +13,7 @@ build: post_install: - pip install poetry - poetry config virtualenvs.create false - - poetry install --with=docs + - poetry install --with=dev # Build documentation in the docs/ directory with Sphinx sphinx: From 82946b969b358366ed443860144fcdd73bcb4eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:34:57 +0100 Subject: [PATCH 060/192] moved docs dependencies to docs group --- .readthedocs.yaml | 2 +- poetry.lock | 12 +++++++----- pyproject.toml | 10 +++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 4ce2983a..1302af38 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,7 +13,7 @@ build: post_install: - pip install poetry - poetry config virtualenvs.create false - - poetry install --with=dev + - poetry install --with=docs # Build documentation in the docs/ directory with Sphinx sphinx: diff --git a/poetry.lock b/poetry.lock index cbeb64e4..24c7278f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. [[package]] name = "absl-py" @@ -847,9 +847,11 @@ files = [ ] [package.dependencies] +absl-py = {version = "*", optional = true, markers = "extra == \"etqdm\""} fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} numpy = {version = "*", optional = true, markers = "extra == \"enp\""} +tqdm = {version = "*", optional = true, markers = "extra == \"etqdm\""} typing_extensions = {version = "*", optional = true, markers = "extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} @@ -987,8 +989,8 @@ files = [ jax = ">=0.4.19" msgpack = "*" numpy = [ - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, {version = ">=1.22", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] optax = "*" orbax-checkpoint = "*" @@ -1464,8 +1466,8 @@ files = [ [package.dependencies] ml-dtypes = ">=0.2.0" numpy = [ - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, {version = ">=1.22", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] opt-einsum = "*" scipy = ">=1.9" @@ -2138,7 +2140,7 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.23.3", markers = "python_version > \"3.10\""}, - {version = ">=1.21.2", markers = "python_version > \"3.9\" and python_version <= \"3.10\""}, + {version = ">=1.21.2", markers = "python_version > \"3.9\""}, ] [package.extras] @@ -4498,4 +4500,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "f278d560dc4fc1546894537db9ec71d02379e610fe7078b085ba8f14d976ddc3" +content-hash = "3894cfd01d961cc48d08cc67703898f9dfbce38717ac0116666f4c38efc8bf0f" diff --git a/pyproject.toml b/pyproject.toml index b85a93b9..6126d03f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,11 +39,6 @@ matplotlib = "^3.6.2" pre-commit = "^2.20.0" isort = "^5.10.1" flake8 = "^5.0.4" -nbsphinx = "^0.9.3" -nbsphinx-link = "^1.3.0" -ipykernel = "^6.29.3" -pandoc = "^2.3" -sphinx-autodoc-typehints = "^2.0.0" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" @@ -51,6 +46,11 @@ sphinx-rtd-theme = "^1.3.0" myst-parser = "^2.0.0" sphinx-copybutton = "^0.5.2" furo = "^2023.9.10" +nbsphinx = "^0.9.3" +nbsphinx-link = "^1.3.0" +ipykernel = "^6.29.3" +pandoc = "^2.3" +sphinx-autodoc-typehints = "^2.0.0" [build-system] requires = ["poetry-core"] From f5a7fd1f7b48d20353ccefbb7c607f2d5f950f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:46:05 +0100 Subject: [PATCH 061/192] removed autodoc typehints --- docs/source/conf.py | 1 - poetry.lock | 471 +++++++++++++++++++++----------------------- pyproject.toml | 1 - 3 files changed, 221 insertions(+), 252 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index da514999..3e5717f9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,6 @@ extensions = [ "sphinx.ext.autodoc", - "sphinx_autodoc_typehints", "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.mathjax", diff --git a/poetry.lock b/poetry.lock index 24c7278f..34a7f6b7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "absl-py" -version = "1.4.0" +version = "2.1.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d"}, - {file = "absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47"}, + {file = "absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff"}, + {file = "absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308"}, ] [[package]] @@ -446,22 +446,23 @@ numpy = "*" [[package]] name = "chex" -version = "0.1.85" +version = "0.1.7" description = "Chex: Testing made fun, in JAX!" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "chex-0.1.85-py3-none-any.whl", hash = "sha256:32c96719aa94045339174138a6aec14aed2630a8a17fb2633ad3eb868890551d"}, - {file = "chex-0.1.85.tar.gz", hash = "sha256:a27cfe87119d6e1fe24ccc1438a59195e6dc1d6e0e10099fcf618c3f64771faf"}, + {file = "chex-0.1.7-py3-none-any.whl", hash = "sha256:9f583015303b1205443843c0b55849bb287f1dfdbd22d9907b1ebb04f964d93e"}, + {file = "chex-0.1.7.tar.gz", hash = "sha256:74ed49799ac4d229881456d468136f1b19a9f9839e3de72b058824e2a4f4dedd"}, ] [package.dependencies] absl-py = ">=0.9.0" -jax = ">=0.4.16" +dm-tree = ">=0.1.5" +jax = ">=0.4.6" jaxlib = ">=0.1.37" -numpy = ">=1.24.1" +numpy = ">=1.18.0" toolz = ">=0.9.0" -typing-extensions = ">=4.2.0" +typing-extensions = {version = ">=4.2.0", markers = "python_version < \"3.11\""} [[package]] name = "click" @@ -1122,13 +1123,13 @@ sphinx-basic-ng = "*" [[package]] name = "gast" -version = "0.5.4" +version = "0.4.0" description = "Python AST that abstracts the underlying Python version" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "gast-0.5.4-py3-none-any.whl", hash = "sha256:6fc4fa5fa10b72fb8aab4ae58bcb023058386e67b6fa2e3e34cec5c769360316"}, - {file = "gast-0.5.4.tar.gz", hash = "sha256:9c270fe5f4b130969b54174de7db4e764b09b4f7f67ccfc32480e29f78348d97"}, + {file = "gast-0.4.0-py3-none-any.whl", hash = "sha256:b7adcdd5adbebf1adf17378da5ba3f543684dbec47b1cda1f3997e573cd542c4"}, + {file = "gast-0.4.0.tar.gz", hash = "sha256:40feb7b8b8434785585ab224d1568b857edb18297e5a3047f1ba012bc83b42c1"}, ] [[package]] @@ -1156,13 +1157,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-auth-oauthlib" -version = "1.2.0" +version = "1.0.0" description = "Google Authentication Library" optional = false python-versions = ">=3.6" files = [ - {file = "google-auth-oauthlib-1.2.0.tar.gz", hash = "sha256:292d2d3783349f2b0734a0a0207b1e1e322ac193c2c09d8f7c613fb7cc501ea8"}, - {file = "google_auth_oauthlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:297c1ce4cb13a99b5834c74a1fe03252e1e499716718b190f56bcb9c4abc4faf"}, + {file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"}, + {file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"}, ] [package.dependencies] @@ -1666,13 +1667,12 @@ files = [ [[package]] name = "keras" -version = "2.15.0" +version = "2.12.0" description = "Deep learning for humans." optional = false python-versions = ">=3.8" files = [ - {file = "keras-2.15.0-py3-none-any.whl", hash = "sha256:2dcc6d2e30cf9c951064b63c1f4c404b966c59caf09e01f3549138ec8ee0dd1f"}, - {file = "keras-2.15.0.tar.gz", hash = "sha256:81871d298c064dc4ac6b58440fdae67bfcf47c8d7ad28580fab401834c06a575"}, + {file = "keras-2.12.0-py2.py3-none-any.whl", hash = "sha256:35c39534011e909645fb93515452e98e1a0ce23727b55d4918b9c58b2308c15e"}, ] [[package]] @@ -2113,34 +2113,34 @@ six = "*" [[package]] name = "ml-dtypes" -version = "0.2.0" +version = "0.3.2" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "ml_dtypes-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df6a76e1c8adf484feb138ed323f9f40a7b6c21788f120f7c78bec20ac37ee81"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc29a0524ef5e23a7fbb8d881bdecabeb3fc1d19d9db61785d077a86cb94fab2"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08c391c2794f2aad358e6f4c70785a9a7b1df980ef4c232b3ccd4f6fe39f719"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:75015818a7fccf99a5e8ed18720cb430f3e71a8838388840f4cdf225c036c983"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e70047ec2c83eaee01afdfdabee2c5b0c133804d90d0f7db4dd903360fcc537c"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36d28b8861a8931695e5a31176cad5ae85f6504906650dea5598fbec06c94606"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85ba8e24cf48d456e564688e981cf379d4c8e644db0a2f719b78de281bac2ca"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:832a019a1b6db5c4422032ca9940a990fa104eee420f643713241b3a518977fa"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8faaf0897942c8253dd126662776ba45f0a5861968cf0f06d6d465f8a7bc298a"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b984cddbe8173b545a0e3334fe56ea1a5c3eb67c507f60d0cfde1d3fa8f8c2"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:022d5a4ee6be14569c2a9d1549e16f1ec87ca949681d0dca59995445d5fcdd5b"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:50845af3e9a601810751b55091dee6c2562403fa1cb4e0123675cf3a4fc2c17a"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f00c71c8c63e03aff313bc6a7aeaac9a4f1483a921a6ffefa6d4404efd1af3d0"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80d304c836d73f10605c58ccf7789c171cc229bfb678748adfb7cea2510dfd0e"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32107e7fa9f62db9a5281de923861325211dfff87bd23faefb27b303314635ab"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:1749b60348da71fd3c2ab303fdbc1965958dc50775ead41f5669c932a341cafd"}, - {file = "ml_dtypes-0.2.0.tar.gz", hash = "sha256:6488eb642acaaf08d8020f6de0a38acee7ac324c1e6e92ee0c0fea42422cb797"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7afde548890a92b41c0fed3a6c525f1200a5727205f73dc21181a2726571bb53"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a746fe5fb9cd974a91070174258f0be129c592b93f9ce7df6cc336416c3fbd"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961134ea44c7b8ca63eda902a44b58cd8bd670e21d62e255c81fba0a8e70d9b7"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:6b35c4e8ca957c877ac35c79ffa77724ecc3702a1e4b18b08306c03feae597bb"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:763697ab8a88d47443997a7cdf3aac7340049aed45f7521f6b0ec8a0594821fe"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89b194e9501a92d289c1ffd411380baf5daafb9818109a4f49b0a1b6dce4462"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c34f2ba9660b21fe1034b608308a01be82bbef2a92fb8199f24dc6bad0d5226"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:6604877d567a29bfe7cc02969ae0f2425260e5335505cf5e7fefc3e5465f5655"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:93b78f53431c93953f7850bb1b925a17f0ab5d97527e38a7e865b5b4bc5cfc18"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a17ef2322e60858d93584e9c52a5be7dd6236b056b7fa1ec57f1bb6ba043e33"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8505946df1665db01332d885c2020b4cb9e84a8b1241eb4ba69d59591f65855"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:f47619d978ab1ae7dfdc4052ea97c636c6263e1f19bd1be0e42c346b98d15ff4"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7b3fb3d4f6b39bcd4f6c4b98f406291f0d681a895490ee29a0f95bab850d53c"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a4c3fcbf86fa52d0204f07cfd23947ef05b4ad743a1a988e163caa34a201e5e"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91f8783fd1f2c23fd3b9ee5ad66b785dafa58ba3cdb050c4458021fa4d1eb226"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ba8e1fafc7fff3e643f453bffa7d082df1678a73286ce8187d3e825e776eb94"}, + {file = "ml_dtypes-0.3.2.tar.gz", hash = "sha256:533059bc5f1764fac071ef54598db358c167c51a718f68f5bb55e3dee79d2967"}, ] [package.dependencies] numpy = [ - {version = ">=1.23.3", markers = "python_version > \"3.10\""}, - {version = ">=1.21.2", markers = "python_version > \"3.9\""}, + {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, ] [package.extras] @@ -2148,67 +2148,67 @@ dev = ["absl-py", "pyink", "pylint (>=2.6.0)", "pytest", "pytest-xdist"] [[package]] name = "msgpack" -version = "1.0.7" +version = "1.0.8" description = "MessagePack serializer" optional = false python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"}, - {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"}, - {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"}, - {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"}, - {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"}, - {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"}, - {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"}, - {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"}, - {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"}, - {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"}, - {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"}, - {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"}, ] [[package]] @@ -2389,47 +2389,39 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.26.4" -description = "Fundamental package for array computing in Python" +version = "1.23.5" +description = "NumPy is the fundamental package for array computing with Python." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-1.23.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c88793f78fca17da0145455f0d7826bcb9f37da4764af27ac945488116efe63"}, + {file = "numpy-1.23.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e9f4c4e51567b616be64e05d517c79a8a22f3606499941d97bb76f2ca59f982d"}, + {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7903ba8ab592b82014713c491f6c5d3a1cde5b4a3bf116404e08f5b52f6daf43"}, + {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e05b1c973a9f858c74367553e236f287e749465f773328c8ef31abe18f691e1"}, + {file = "numpy-1.23.5-cp310-cp310-win32.whl", hash = "sha256:522e26bbf6377e4d76403826ed689c295b0b238f46c28a7251ab94716da0b280"}, + {file = "numpy-1.23.5-cp310-cp310-win_amd64.whl", hash = "sha256:dbee87b469018961d1ad79b1a5d50c0ae850000b639bcb1b694e9981083243b6"}, + {file = "numpy-1.23.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ce571367b6dfe60af04e04a1834ca2dc5f46004ac1cc756fb95319f64c095a96"}, + {file = "numpy-1.23.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56e454c7833e94ec9769fa0f86e6ff8e42ee38ce0ce1fa4cbb747ea7e06d56aa"}, + {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5039f55555e1eab31124a5768898c9e22c25a65c1e0037f4d7c495a45778c9f2"}, + {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f545efd1108e647604a1b5aa809591ccd2540f468a880bedb97247e72db387"}, + {file = "numpy-1.23.5-cp311-cp311-win32.whl", hash = "sha256:b2a9ab7c279c91974f756c84c365a669a887efa287365a8e2c418f8b3ba73fb0"}, + {file = "numpy-1.23.5-cp311-cp311-win_amd64.whl", hash = "sha256:0cbe9848fad08baf71de1a39e12d1b6310f1d5b2d0ea4de051058e6e1076852d"}, + {file = "numpy-1.23.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f063b69b090c9d918f9df0a12116029e274daf0181df392839661c4c7ec9018a"}, + {file = "numpy-1.23.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0aaee12d8883552fadfc41e96b4c82ee7d794949e2a7c3b3a7201e968c7ecab9"}, + {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c8c1e89a1f5028a4c6d9e3ccbe311b6ba53694811269b992c0b224269e2398"}, + {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d208a0f8729f3fb790ed18a003f3a57895b989b40ea4dce4717e9cf4af62c6bb"}, + {file = "numpy-1.23.5-cp38-cp38-win32.whl", hash = "sha256:06005a2ef6014e9956c09ba07654f9837d9e26696a0470e42beedadb78c11b07"}, + {file = "numpy-1.23.5-cp38-cp38-win_amd64.whl", hash = "sha256:ca51fcfcc5f9354c45f400059e88bc09215fb71a48d3768fb80e357f3b457e1e"}, + {file = "numpy-1.23.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8969bfd28e85c81f3f94eb4a66bc2cf1dbdc5c18efc320af34bffc54d6b1e38f"}, + {file = "numpy-1.23.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7ac231a08bb37f852849bbb387a20a57574a97cfc7b6cabb488a4fc8be176de"}, + {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf837dc63ba5c06dc8797c398db1e223a466c7ece27a1f7b5232ba3466aafe3d"}, + {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33161613d2269025873025b33e879825ec7b1d831317e68f4f2f0f84ed14c719"}, + {file = "numpy-1.23.5-cp39-cp39-win32.whl", hash = "sha256:af1da88f6bc3d2338ebbf0e22fe487821ea4d8e89053e25fa59d1d79786e7481"}, + {file = "numpy-1.23.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b7847f7e83ca37c6e627682f145856de331049013853f344f37b0c9690e3df"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:abdde9f795cf292fb9651ed48185503a2ff29be87770c3b8e2a14b0cd7aa16f8"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a909a8bae284d46bbfdefbdd4a262ba19d3bc9921b1e76126b1d21c3c34135"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:01dd17cbb340bf0fc23981e52e1d18a9d4050792e8fb8363cecbf066a84b827d"}, + {file = "numpy-1.23.5.tar.gz", hash = "sha256:1b1766d6f397c18153d40015ddfc79ddb715cabadc04d2d228d4e5a8bc4ded1a"}, ] [[package]] @@ -2492,13 +2484,13 @@ test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] [[package]] name = "orbax-checkpoint" -version = "0.4.4" +version = "0.5.3" description = "Orbax Checkpoint" optional = false python-versions = ">=3.9" files = [ - {file = "orbax_checkpoint-0.4.4-py3-none-any.whl", hash = "sha256:e356288d7f62b30519b20ae3c0584743d6598234e4996b4c15bbbd32c13c1f04"}, - {file = "orbax_checkpoint-0.4.4.tar.gz", hash = "sha256:85ab96268b3f39e83809254cb3d55aa5a47c2279d7d3e725bd5f7c2da10a4de9"}, + {file = "orbax_checkpoint-0.5.3-py3-none-any.whl", hash = "sha256:82acdf18acb1e294396dd583634d3b1bd005bbb81f3de650740384c465d735c3"}, + {file = "orbax_checkpoint-0.5.3.tar.gz", hash = "sha256:1572904cbbfe8513927e0d80f80b730e0ef2f680332d3c2810d8443532938b45"}, ] [package.dependencies] @@ -2511,7 +2503,7 @@ nest_asyncio = "*" numpy = "*" protobuf = "*" pyyaml = "*" -tensorstore = ">=0.1.35" +tensorstore = ">=0.1.51" typing_extensions = "*" [package.extras] @@ -2919,13 +2911,13 @@ files = [ [[package]] name = "pydantic" -version = "2.6.2" +version = "2.6.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, - {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, ] [package.dependencies] @@ -3129,13 +3121,13 @@ testing = ["filelock"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.tar.gz", hash = "sha256:78e73e19c63f5b20ffa567001531680d939dc042bf7850431877645523c66709"}, + {file = "python_dateutil-2.9.0-py2.py3-none-any.whl", hash = "sha256:cbf2f1da5e6083ac2fbfd4da39a25f34312230110440f424a14c7558bb85d82e"}, ] [package.dependencies] @@ -3648,25 +3640,6 @@ docs = ["sphinxcontrib-websupport"] lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools (>=67.0)"] -[[package]] -name = "sphinx-autodoc-typehints" -version = "2.0.0" -description = "Type hints (PEP 484) support for the Sphinx autodoc extension" -optional = false -python-versions = ">=3.8" -files = [ - {file = "sphinx_autodoc_typehints-2.0.0-py3-none-any.whl", hash = "sha256:12c0e161f6fe191c2cdfd8fa3caea271f5387d9fbc67ebcd6f4f1f24ce880993"}, - {file = "sphinx_autodoc_typehints-2.0.0.tar.gz", hash = "sha256:7f2cdac2e70fd9787926b6e9e541cd4ded1e838d2b46fda2a1bb0a75ec5b7f3a"}, -] - -[package.dependencies] -sphinx = ">=7.1.2" - -[package.extras] -docs = ["furo (>=2023.9.10)"] -numpy = ["nptyping (>=2.5)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.8)"] - [[package]] name = "sphinx-basic-ng" version = "1.0.0b2" @@ -3850,27 +3823,27 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "tensorboard" -version = "2.15.2" +version = "2.12.3" description = "TensorBoard lets you watch Tensors Flow" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "tensorboard-2.15.2-py3-none-any.whl", hash = "sha256:a6f6443728064d962caea6d34653e220e34ef8df764cb06a8212c17e1a8f0622"}, + {file = "tensorboard-2.12.3-py3-none-any.whl", hash = "sha256:b4a69366784bc347e02fbe7d847e01896a649ca52f8948a11005e205dcf724fb"}, ] [package.dependencies] absl-py = ">=0.4" google-auth = ">=1.6.3,<3" -google-auth-oauthlib = ">=0.5,<2" +google-auth-oauthlib = ">=0.5,<1.1" grpcio = ">=1.48.2" markdown = ">=2.6.8" numpy = ">=1.12.0" -protobuf = ">=3.19.6,<4.24.0 || >4.24.0" +protobuf = ">=3.19.6" requests = ">=2.21.0,<3" setuptools = ">=41.0.0" -six = ">1.9" tensorboard-data-server = ">=0.7.0,<0.8.0" werkzeug = ">=1.0.1" +wheel = ">=0.26" [[package]] name = "tensorboard-data-server" @@ -3886,100 +3859,98 @@ files = [ [[package]] name = "tensorflow" -version = "2.15.0" +version = "2.12.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "tensorflow-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:9b248e0f4316b3a3c54cd1f83edfb7a761d473060c1972a8ea31a90d5de3aa72"}, - {file = "tensorflow-2.15.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:eaf420d8b8ec1d4bd75859be7d7545d8e7052726eed8456fdbba63718e7e07ea"}, - {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98aab454fc73ff1900314821e5bafbf20840ada2004c8caccf4d92e0e12a628"}, - {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed601b43df9b7d9bed0203b34bcb9356efd4f671eaaac1046b7166a2afee0cf8"}, - {file = "tensorflow-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:2d88f8b71f4a8d9ab9dc7c8e42b14ca0f53d1daab0f989b8f2918907c2891f41"}, - {file = "tensorflow-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1e0716622ed7af867d8b1997b00a2940f1a1587dee923ff53efa2ee506992f32"}, - {file = "tensorflow-2.15.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:124930e7d4f5d74c61a5c80d642a26c22fe0c42fdd383fe9ee5803c3ac9ed4ce"}, - {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852efeb4d18beedac0120c4f2d4f4dccf4c090bb6740c5199d395ff609e85e98"}, - {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee8ec2b2c6c942ae65d25746e53cdc475e82d5fcbbb3009ce47f5963d69ebfc"}, - {file = "tensorflow-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:e05a48006930e4e9e68468e7affed3bbce8a1c7fe6df86500496ad1558804a78"}, - {file = "tensorflow-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2cfcdde1ff3c01be617e99ce9783c49cb11da5796ce32a31855412bd092c0bcf"}, - {file = "tensorflow-2.15.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:896bda03f722700a9918d144aee5152a75f1be5e6c5045fd0683b8318a3fc9d9"}, - {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7697b005ce48fec8b2ee8cf25bcbd138f16b5e17f99f7c01a6ea3f2429f86c6"}, - {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa865956d96b7614f247c36e4c22b1543ba5ce656fbe8e4f6266ae7a4917132"}, - {file = "tensorflow-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:01108746e1bbfcd48dfabf7f51ddca7693b91ea6821f6f62a27b5a5ebf0817c5"}, + {file = "tensorflow-2.12.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:be4ac0dfcc7a16f6df2bc19bd322e312235ab3f7b0c7297f96c92c44bb14d2a1"}, + {file = "tensorflow-2.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5193ddb3bb5120cb445279beb08ed9e74a85a4eeb2485550d6fb707a89d9a88"}, + {file = "tensorflow-2.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357d9d2851188a8d27ee195345b4d175cad970150d1344ba9d9fcc4bf2b68336"}, + {file = "tensorflow-2.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c8001210df7202ef6267150865b0b79f834c3ca69ee3132277de8eeb994dffde"}, + {file = "tensorflow-2.12.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:91dccda42c03569d8c787190482a11ecae3b9b173aaa9166f0ab20cecc9c31f4"}, + {file = "tensorflow-2.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f81eb8adaeb558963f5d8b47dbfcc398d898f0857bf3de6b6484350236b7b5"}, + {file = "tensorflow-2.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ec4a2934ea19e92f27a9668ece43025ed5efe14b5d19be53b07692bc8a4189d"}, + {file = "tensorflow-2.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e7641e2a6e32f31ff233495478a9cc86b7c038140eab714a61eeddbbbb327c3"}, + {file = "tensorflow-2.12.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:a7194e744c5a7f3e759ecb949527b4a07718a6d1110e6e82fd4ce0c5586a7d4a"}, + {file = "tensorflow-2.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4afc2dd57435f29ebe249eb5f595d89b0e73be94922eeb7110aa6280a332837c"}, + {file = "tensorflow-2.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23850332f1f9f778d697c9dba63ca52be72cb73363e75ad358f07ddafef63c01"}, + {file = "tensorflow-2.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:e29fcf6cfd069aefb4b44f357cccbb4415a5a3d7b5b516eaf4450062fe40021e"}, + {file = "tensorflow-2.12.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:42fc2635e9420faee781a16bd393126f29cd39aa2b9d02901f24d8497bd6f958"}, + {file = "tensorflow-2.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76414355e420edb9154b4e72113eef5813ccb71701fda959afbbc1eebe3099bd"}, + {file = "tensorflow-2.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:020d6a54cb26020bdc71a7bae8ee35be05096f63e773dc517f6e87c49de62c50"}, + {file = "tensorflow-2.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:9f70a8f9ab46e5ed436850aa60d1cd40645f5c669e14bcad48915dc1f597dda2"}, ] [package.dependencies] absl-py = ">=1.0.0" astunparse = ">=1.6.0" -flatbuffers = ">=23.5.26" -gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" +flatbuffers = ">=2.0" +gast = ">=0.2.1,<=0.4.0" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -keras = ">=2.15.0,<2.16" +jax = ">=0.3.15" +keras = ">=2.12.0,<2.13" libclang = ">=13.0.0" -ml-dtypes = ">=0.2.0,<0.3.0" -numpy = ">=1.23.5,<2.0.0" +numpy = ">=1.22,<1.24" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.15,<2.16" -tensorflow-estimator = ">=2.15.0,<2.16" -tensorflow-io-gcs-filesystem = ">=0.23.1" +tensorboard = ">=2.12,<2.13" +tensorflow-estimator = ">=2.12.0,<2.13" +tensorflow-io-gcs-filesystem = {version = ">=0.23.1", markers = "platform_machine != \"arm64\" or platform_system != \"Darwin\""} termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" -[package.extras] -and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] - [[package]] name = "tensorflow-cpu" -version = "2.15.0" +version = "2.12.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "tensorflow_cpu-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:67bac86d3fce227e59fdd31d1ac45e25cfa2f2c0a3a1269b1d2acf5721fcb7af"}, - {file = "tensorflow_cpu-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f60b3d4270a507eef10d9da5ab55fdec90a4c77c664dde446709b597f0864a62"}, - {file = "tensorflow_cpu-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc52cdceb0f2e5853599e9226987ba8f260347b5b1591c8efb60b13ba2ea9fa8"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b0b2986a6cf63053c1f63bc751b228f5478283c0aa66a58271e931ae318978ce"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46c795177f6311c83562e05d38dc7d4618f8d3150e6902a4499b875f3f97270"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:4487d0991e6f71bb56000f49a8ba467786b1ed7fafc7a6c0fad6d10ea46fc304"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f02026dbb9c2d953d27d2c44de65ecf5e42f002750ae560b63484e50f869a16f"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfd3bdc43e29a9239d05f4c116c2fb7c38dd388222d3c934138dfbcb93e5a506"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:6900344496f0defd54c5da4aa2228bf0f332fb0a6cb5136b90b3541a6e4322d6"}, + {file = "tensorflow_cpu-2.12.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:734ce850e2b3493041bdc071b594f0f78d35e4bfce5a7e0a98d449b20420e01d"}, + {file = "tensorflow_cpu-2.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361b19b5a64bf611beccd22de1fc04f614a8c157ac99893d9702ed24932018d6"}, + {file = "tensorflow_cpu-2.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:d5ad746bf8c87d9a9fcea4698828ba1d101a7f7bfd323a2571130374a192578b"}, + {file = "tensorflow_cpu-2.12.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b9c8f0d0658da8a5b25a4fe5ca315f86c449eb11e30d79cea49c7658be75a825"}, + {file = "tensorflow_cpu-2.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c7047552a2d759f3e65ac13e36dd24bb5fec2e6576e848287811ec44b3d62f"}, + {file = "tensorflow_cpu-2.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fdb636736f95094368bc7d26bb3b8ed93ba820cc5d95f847e00bf4a7645463d"}, + {file = "tensorflow_cpu-2.12.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5beeb99d2a1cc1383ca981513c35a4a18157e52d91a89e69c94cb7b7e411f0d8"}, + {file = "tensorflow_cpu-2.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a406f751180fe5282776e8bc84f39a2dc2b796c3ae35fbe20e4edc86ec580dd3"}, + {file = "tensorflow_cpu-2.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:b6ba926f9a56cdf0657defc6d046735e31ded383054f67c1a16ef2b0511f68d7"}, + {file = "tensorflow_cpu-2.12.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:ef4f142b6fe75fcc71ada6331ed2a15ed61b7034187049d0ef1dac482d52db78"}, + {file = "tensorflow_cpu-2.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55685b9a19c8ecb2587fb53914c045b188ed0289a2c6495e4e59d5fb082da9cc"}, + {file = "tensorflow_cpu-2.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:374b15d1cec1a62006e388062e89dd4899a121272d41ea5d3fcbcc96e2d875c9"}, ] [package.dependencies] absl-py = ">=1.0.0" astunparse = ">=1.6.0" -flatbuffers = ">=23.5.26" -gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" +flatbuffers = ">=2.0" +gast = ">=0.2.1,<=0.4.0" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -keras = ">=2.15.0,<2.16" +jax = ">=0.3.15" +keras = ">=2.12.0,<2.13" libclang = ">=13.0.0" -ml-dtypes = ">=0.2.0,<0.3.0" -numpy = ">=1.23.5,<2.0.0" +numpy = ">=1.22,<1.24" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.15,<2.16" -tensorflow-estimator = ">=2.15.0,<2.16" -tensorflow-io-gcs-filesystem = ">=0.23.1" +tensorboard = ">=2.12,<2.13" +tensorflow-estimator = ">=2.12.0,<2.13" +tensorflow-io-gcs-filesystem = {version = ">=0.23.1", markers = "platform_machine != \"arm64\" or platform_system != \"Darwin\""} termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" -[package.extras] -and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] - [[package]] name = "tensorflow-datasets" version = "4.9.4" @@ -4048,12 +4019,12 @@ youtube-vis = ["pycocotools"] [[package]] name = "tensorflow-estimator" -version = "2.15.0" +version = "2.12.0" description = "TensorFlow Estimator." optional = false python-versions = ">=3.7" files = [ - {file = "tensorflow_estimator-2.15.0-py2.py3-none-any.whl", hash = "sha256:aedf21eec7fb2dc91150fc91a1ce12bc44dbb72278a08b58e79ff87c9e28f153"}, + {file = "tensorflow_estimator-2.12.0-py2.py3-none-any.whl", hash = "sha256:59b191bead4883822de3d63ac02ace11a83bfe6c10d64d0c4dfde75a50e60ca1"}, ] [[package]] @@ -4087,46 +4058,46 @@ tensorflow-rocm = ["tensorflow-rocm (>=2.15.0,<2.16.0)"] [[package]] name = "tensorflow-metadata" -version = "1.14.0" +version = "0.22.2" description = "Library and standards for schema and statistics." optional = false -python-versions = ">=3.8,<4" +python-versions = ">=2.7,<4" files = [ - {file = "tensorflow_metadata-1.14.0-py3-none-any.whl", hash = "sha256:5ff79bf96f98c800fc08270b852663afe7e74d7e1f92b50ba1487bfc63894cdb"}, + {file = "tensorflow_metadata-0.22.2-py2.py3-none-any.whl", hash = "sha256:f9ffde743dd61f775f35872e79c4eefecbc539a8870e57b20359dc74726f06eb"}, ] [package.dependencies] -absl-py = ">=0.9,<2.0.0" -googleapis-common-protos = ">=1.52.0,<2" -protobuf = ">=3.20.3,<4.21" +googleapis-common-protos = "*" +protobuf = ">=3.7,<4" [[package]] name = "tensorstore" -version = "0.1.45" +version = "0.1.54" description = "Read and write large, multi-dimensional arrays" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tensorstore-0.1.45-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:2ff6e5177ba2702f348bef3edc37619aa7646e43f33d1a567ba267db455699e4"}, - {file = "tensorstore-0.1.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bc7cde6318363eb9d35fc6cacb6fcd5d7a03b0ee57bdd69249108c0164692d8"}, - {file = "tensorstore-0.1.45-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405bf40271eed5632a566cdb935beba87d9896d2f80caf75386febb529ddba45"}, - {file = "tensorstore-0.1.45-cp310-cp310-win_amd64.whl", hash = "sha256:537805adb06fff2ce9a259b81920af4c34a20f752fa28205e722b7e58a60c790"}, - {file = "tensorstore-0.1.45-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:73df4ddafe4da8e0f919ed5a75f48839013da3a99128a719fe730855252051a6"}, - {file = "tensorstore-0.1.45-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f38bba6fc0668a950b76752c743b66851c4fc7360857e8b37a4f7a4e9786760b"}, - {file = "tensorstore-0.1.45-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca212d127fcc4debb9f6b4274d584fe7724b2a349ca9444258a4127878dc3033"}, - {file = "tensorstore-0.1.45-cp311-cp311-win_amd64.whl", hash = "sha256:a8960f0e546ee493ed67b77998859f0cb94772ea31e865bf76b0c79976ac9204"}, - {file = "tensorstore-0.1.45-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:871a1fde0712a153ac44774ddace3ad841609ff5be792734d44cffb520258e92"}, - {file = "tensorstore-0.1.45-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0ce1a3d2bdbdb2c1102100ee23fa99a95b0bcdee9773862622d7da833516c8c9"}, - {file = "tensorstore-0.1.45-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8659688ec9d89cdd71046c35b3c84cf92cd8c88251e6068f8a99d6991a965028"}, - {file = "tensorstore-0.1.45-cp38-cp38-win_amd64.whl", hash = "sha256:c034fec18b6e3174d26df1cdd91ec67b720fc5de7ef0cc3804017dad8c211622"}, - {file = "tensorstore-0.1.45-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4915aee8355ee7dbc6f534d77a28c18001e19696f44f78760ec42845ac51edee"}, - {file = "tensorstore-0.1.45-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4346ab7afa0963dcaa8e64388a2bedab741c790786b577326a0b174d226c9320"}, - {file = "tensorstore-0.1.45-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05196a0464ce51867f1edd96e992fe01281de283b034d434ca6e81db319368c0"}, - {file = "tensorstore-0.1.45-cp39-cp39-win_amd64.whl", hash = "sha256:6d7b6cccb96b36356d3e61c4e89972b82123d799cc2ca50f743e30ce45d70739"}, - {file = "tensorstore-0.1.45.tar.gz", hash = "sha256:38468c621b2edf09cfdd2df4905890e83f1805c7645ec13e16df5eafabf0e5e5"}, + {file = "tensorstore-0.1.54-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:54dbc2d5de635ff55c4dd1e85eb8d326ed7c0c90489ab8e9dbbc93ad70f4ebf6"}, + {file = "tensorstore-0.1.54-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3d62cec4f3257e7e1d60220d6b1a604cf1e6d2f4684407669a3baa4c53b81f47"}, + {file = "tensorstore-0.1.54-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f5e0e9a81b41cba6c7462b57531855e3c0be320ae05b071b220206f04ab3b99"}, + {file = "tensorstore-0.1.54-cp310-cp310-win_amd64.whl", hash = "sha256:2ccfc236cab7d5d7c0fdd6a1e13fbe9e5aa69a8dd0c472f479dd2b8c4c66f563"}, + {file = "tensorstore-0.1.54-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:d2c032e5eb31ab0835fc21c74f5134274fe6d1f147917e1571876e4aa011d206"}, + {file = "tensorstore-0.1.54-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcf6925cc1b1793d888d6c81f3f2bafe8b78352c792a5e77cc519b4fc8fd9482"}, + {file = "tensorstore-0.1.54-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dab3fb3fca3ec23f43d502641fc7ce3f40bdb864eca63b2b10a5a6592014f00b"}, + {file = "tensorstore-0.1.54-cp311-cp311-win_amd64.whl", hash = "sha256:ba5d560d321ad353af866910bcdfb396ccd822b89d50e3275a22193dcbd6e35b"}, + {file = "tensorstore-0.1.54-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:608212a855808f0f55a3cb66a562514632023df9df26e11c8497803102e17303"}, + {file = "tensorstore-0.1.54-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02077de82f9a388badc831b8bef0242f82ce47830076130e0f947bc2db88ecc1"}, + {file = "tensorstore-0.1.54-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e19ef2c20e7139a5ba3f33b3170ff1418d2cffec01b46f16b0428b66984894e"}, + {file = "tensorstore-0.1.54-cp312-cp312-win_amd64.whl", hash = "sha256:68dc970e7f69f46d4b7bcbbcb924e0c5ad71e9a2f16481679430edb1deb65fb0"}, + {file = "tensorstore-0.1.54-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:70de04ad2177fb771f17db1a61cc1ed3295147676021cb3d63649b8a9faf2f45"}, + {file = "tensorstore-0.1.54-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:954f321049ae0fd97904b76f2b8fc49257a04fa5813c8ca4b5aafa92567e743e"}, + {file = "tensorstore-0.1.54-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ddc9c99b34afe3d64e4c2585238ace9d8a9e1818a9ffcdce356e4e20e98648"}, + {file = "tensorstore-0.1.54-cp39-cp39-win_amd64.whl", hash = "sha256:9b0501b40107c0bec29c48ce926353eee92b2b6d3b5d5bce0983c35de007eaaf"}, + {file = "tensorstore-0.1.54.tar.gz", hash = "sha256:e1a9dcb0be7c828f752375409537d4b39c658dd6c6a0873fe21a24a556ec0e2a"}, ] [package.dependencies] +ml-dtypes = ">=0.3.1" numpy = ">=1.16.0" [[package]] @@ -4500,4 +4471,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "3894cfd01d961cc48d08cc67703898f9dfbce38717ac0116666f4c38efc8bf0f" +content-hash = "ebc44a0bc64bb8f90db4e98f4fc8b90bf927e5383a7ec4a2d8b67d6f7f48b4a9" diff --git a/pyproject.toml b/pyproject.toml index 6126d03f..81e5df6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,6 @@ nbsphinx = "^0.9.3" nbsphinx-link = "^1.3.0" ipykernel = "^6.29.3" pandoc = "^2.3" -sphinx-autodoc-typehints = "^2.0.0" [build-system] requires = ["poetry-core"] From 78322c30c64d062d362a15745674f52037917478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 14:59:29 +0100 Subject: [PATCH 062/192] set venv in rtd --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1302af38..4960fa77 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,7 +13,7 @@ build: post_install: - pip install poetry - poetry config virtualenvs.create false - - poetry install --with=docs + - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs #poetry install --with=docs # Build documentation in the docs/ directory with Sphinx sphinx: From 283b711c3f0cea6e7cb393d186413e9470db8047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 15:25:18 +0100 Subject: [PATCH 063/192] bump chex version --- poetry.lock | 307 +++++++++++++++++++++++++------------------------ pyproject.toml | 2 +- 2 files changed, 159 insertions(+), 150 deletions(-) diff --git a/poetry.lock b/poetry.lock index 34a7f6b7..e7a6cc89 100644 --- a/poetry.lock +++ b/poetry.lock @@ -446,23 +446,22 @@ numpy = "*" [[package]] name = "chex" -version = "0.1.7" +version = "0.1.85" description = "Chex: Testing made fun, in JAX!" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "chex-0.1.7-py3-none-any.whl", hash = "sha256:9f583015303b1205443843c0b55849bb287f1dfdbd22d9907b1ebb04f964d93e"}, - {file = "chex-0.1.7.tar.gz", hash = "sha256:74ed49799ac4d229881456d468136f1b19a9f9839e3de72b058824e2a4f4dedd"}, + {file = "chex-0.1.85-py3-none-any.whl", hash = "sha256:32c96719aa94045339174138a6aec14aed2630a8a17fb2633ad3eb868890551d"}, + {file = "chex-0.1.85.tar.gz", hash = "sha256:a27cfe87119d6e1fe24ccc1438a59195e6dc1d6e0e10099fcf618c3f64771faf"}, ] [package.dependencies] absl-py = ">=0.9.0" -dm-tree = ">=0.1.5" -jax = ">=0.4.6" +jax = ">=0.4.16" jaxlib = ">=0.1.37" -numpy = ">=1.18.0" +numpy = ">=1.24.1" toolz = ">=0.9.0" -typing-extensions = {version = ">=4.2.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.2.0" [[package]] name = "click" @@ -1123,13 +1122,13 @@ sphinx-basic-ng = "*" [[package]] name = "gast" -version = "0.4.0" +version = "0.5.4" description = "Python AST that abstracts the underlying Python version" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "gast-0.4.0-py3-none-any.whl", hash = "sha256:b7adcdd5adbebf1adf17378da5ba3f543684dbec47b1cda1f3997e573cd542c4"}, - {file = "gast-0.4.0.tar.gz", hash = "sha256:40feb7b8b8434785585ab224d1568b857edb18297e5a3047f1ba012bc83b42c1"}, + {file = "gast-0.5.4-py3-none-any.whl", hash = "sha256:6fc4fa5fa10b72fb8aab4ae58bcb023058386e67b6fa2e3e34cec5c769360316"}, + {file = "gast-0.5.4.tar.gz", hash = "sha256:9c270fe5f4b130969b54174de7db4e764b09b4f7f67ccfc32480e29f78348d97"}, ] [[package]] @@ -1157,13 +1156,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-auth-oauthlib" -version = "1.0.0" +version = "1.2.0" description = "Google Authentication Library" optional = false python-versions = ">=3.6" files = [ - {file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"}, - {file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"}, + {file = "google-auth-oauthlib-1.2.0.tar.gz", hash = "sha256:292d2d3783349f2b0734a0a0207b1e1e322ac193c2c09d8f7c613fb7cc501ea8"}, + {file = "google_auth_oauthlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:297c1ce4cb13a99b5834c74a1fe03252e1e499716718b190f56bcb9c4abc4faf"}, ] [package.dependencies] @@ -1667,12 +1666,13 @@ files = [ [[package]] name = "keras" -version = "2.12.0" +version = "2.15.0" description = "Deep learning for humans." optional = false python-versions = ">=3.8" files = [ - {file = "keras-2.12.0-py2.py3-none-any.whl", hash = "sha256:35c39534011e909645fb93515452e98e1a0ce23727b55d4918b9c58b2308c15e"}, + {file = "keras-2.15.0-py3-none-any.whl", hash = "sha256:2dcc6d2e30cf9c951064b63c1f4c404b966c59caf09e01f3549138ec8ee0dd1f"}, + {file = "keras-2.15.0.tar.gz", hash = "sha256:81871d298c064dc4ac6b58440fdae67bfcf47c8d7ad28580fab401834c06a575"}, ] [[package]] @@ -2113,34 +2113,34 @@ six = "*" [[package]] name = "ml-dtypes" -version = "0.3.2" +version = "0.2.0" description = "" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "ml_dtypes-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7afde548890a92b41c0fed3a6c525f1200a5727205f73dc21181a2726571bb53"}, - {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a746fe5fb9cd974a91070174258f0be129c592b93f9ce7df6cc336416c3fbd"}, - {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961134ea44c7b8ca63eda902a44b58cd8bd670e21d62e255c81fba0a8e70d9b7"}, - {file = "ml_dtypes-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:6b35c4e8ca957c877ac35c79ffa77724ecc3702a1e4b18b08306c03feae597bb"}, - {file = "ml_dtypes-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:763697ab8a88d47443997a7cdf3aac7340049aed45f7521f6b0ec8a0594821fe"}, - {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89b194e9501a92d289c1ffd411380baf5daafb9818109a4f49b0a1b6dce4462"}, - {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c34f2ba9660b21fe1034b608308a01be82bbef2a92fb8199f24dc6bad0d5226"}, - {file = "ml_dtypes-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:6604877d567a29bfe7cc02969ae0f2425260e5335505cf5e7fefc3e5465f5655"}, - {file = "ml_dtypes-0.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:93b78f53431c93953f7850bb1b925a17f0ab5d97527e38a7e865b5b4bc5cfc18"}, - {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a17ef2322e60858d93584e9c52a5be7dd6236b056b7fa1ec57f1bb6ba043e33"}, - {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8505946df1665db01332d885c2020b4cb9e84a8b1241eb4ba69d59591f65855"}, - {file = "ml_dtypes-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:f47619d978ab1ae7dfdc4052ea97c636c6263e1f19bd1be0e42c346b98d15ff4"}, - {file = "ml_dtypes-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7b3fb3d4f6b39bcd4f6c4b98f406291f0d681a895490ee29a0f95bab850d53c"}, - {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a4c3fcbf86fa52d0204f07cfd23947ef05b4ad743a1a988e163caa34a201e5e"}, - {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91f8783fd1f2c23fd3b9ee5ad66b785dafa58ba3cdb050c4458021fa4d1eb226"}, - {file = "ml_dtypes-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ba8e1fafc7fff3e643f453bffa7d082df1678a73286ce8187d3e825e776eb94"}, - {file = "ml_dtypes-0.3.2.tar.gz", hash = "sha256:533059bc5f1764fac071ef54598db358c167c51a718f68f5bb55e3dee79d2967"}, + {file = "ml_dtypes-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df6a76e1c8adf484feb138ed323f9f40a7b6c21788f120f7c78bec20ac37ee81"}, + {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc29a0524ef5e23a7fbb8d881bdecabeb3fc1d19d9db61785d077a86cb94fab2"}, + {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08c391c2794f2aad358e6f4c70785a9a7b1df980ef4c232b3ccd4f6fe39f719"}, + {file = "ml_dtypes-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:75015818a7fccf99a5e8ed18720cb430f3e71a8838388840f4cdf225c036c983"}, + {file = "ml_dtypes-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e70047ec2c83eaee01afdfdabee2c5b0c133804d90d0f7db4dd903360fcc537c"}, + {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36d28b8861a8931695e5a31176cad5ae85f6504906650dea5598fbec06c94606"}, + {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85ba8e24cf48d456e564688e981cf379d4c8e644db0a2f719b78de281bac2ca"}, + {file = "ml_dtypes-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:832a019a1b6db5c4422032ca9940a990fa104eee420f643713241b3a518977fa"}, + {file = "ml_dtypes-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8faaf0897942c8253dd126662776ba45f0a5861968cf0f06d6d465f8a7bc298a"}, + {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b984cddbe8173b545a0e3334fe56ea1a5c3eb67c507f60d0cfde1d3fa8f8c2"}, + {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:022d5a4ee6be14569c2a9d1549e16f1ec87ca949681d0dca59995445d5fcdd5b"}, + {file = "ml_dtypes-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:50845af3e9a601810751b55091dee6c2562403fa1cb4e0123675cf3a4fc2c17a"}, + {file = "ml_dtypes-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f00c71c8c63e03aff313bc6a7aeaac9a4f1483a921a6ffefa6d4404efd1af3d0"}, + {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80d304c836d73f10605c58ccf7789c171cc229bfb678748adfb7cea2510dfd0e"}, + {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32107e7fa9f62db9a5281de923861325211dfff87bd23faefb27b303314635ab"}, + {file = "ml_dtypes-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:1749b60348da71fd3c2ab303fdbc1965958dc50775ead41f5669c932a341cafd"}, + {file = "ml_dtypes-0.2.0.tar.gz", hash = "sha256:6488eb642acaaf08d8020f6de0a38acee7ac324c1e6e92ee0c0fea42422cb797"}, ] [package.dependencies] numpy = [ - {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, - {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, + {version = ">=1.23.3", markers = "python_version > \"3.10\""}, + {version = ">=1.21.2", markers = "python_version > \"3.9\""}, ] [package.extras] @@ -2389,39 +2389,47 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.23.5" -description = "NumPy is the fundamental package for array computing with Python." +version = "1.26.4" +description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "numpy-1.23.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c88793f78fca17da0145455f0d7826bcb9f37da4764af27ac945488116efe63"}, - {file = "numpy-1.23.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e9f4c4e51567b616be64e05d517c79a8a22f3606499941d97bb76f2ca59f982d"}, - {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7903ba8ab592b82014713c491f6c5d3a1cde5b4a3bf116404e08f5b52f6daf43"}, - {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e05b1c973a9f858c74367553e236f287e749465f773328c8ef31abe18f691e1"}, - {file = "numpy-1.23.5-cp310-cp310-win32.whl", hash = "sha256:522e26bbf6377e4d76403826ed689c295b0b238f46c28a7251ab94716da0b280"}, - {file = "numpy-1.23.5-cp310-cp310-win_amd64.whl", hash = "sha256:dbee87b469018961d1ad79b1a5d50c0ae850000b639bcb1b694e9981083243b6"}, - {file = "numpy-1.23.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ce571367b6dfe60af04e04a1834ca2dc5f46004ac1cc756fb95319f64c095a96"}, - {file = "numpy-1.23.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56e454c7833e94ec9769fa0f86e6ff8e42ee38ce0ce1fa4cbb747ea7e06d56aa"}, - {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5039f55555e1eab31124a5768898c9e22c25a65c1e0037f4d7c495a45778c9f2"}, - {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f545efd1108e647604a1b5aa809591ccd2540f468a880bedb97247e72db387"}, - {file = "numpy-1.23.5-cp311-cp311-win32.whl", hash = "sha256:b2a9ab7c279c91974f756c84c365a669a887efa287365a8e2c418f8b3ba73fb0"}, - {file = "numpy-1.23.5-cp311-cp311-win_amd64.whl", hash = "sha256:0cbe9848fad08baf71de1a39e12d1b6310f1d5b2d0ea4de051058e6e1076852d"}, - {file = "numpy-1.23.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f063b69b090c9d918f9df0a12116029e274daf0181df392839661c4c7ec9018a"}, - {file = "numpy-1.23.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0aaee12d8883552fadfc41e96b4c82ee7d794949e2a7c3b3a7201e968c7ecab9"}, - {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c8c1e89a1f5028a4c6d9e3ccbe311b6ba53694811269b992c0b224269e2398"}, - {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d208a0f8729f3fb790ed18a003f3a57895b989b40ea4dce4717e9cf4af62c6bb"}, - {file = "numpy-1.23.5-cp38-cp38-win32.whl", hash = "sha256:06005a2ef6014e9956c09ba07654f9837d9e26696a0470e42beedadb78c11b07"}, - {file = "numpy-1.23.5-cp38-cp38-win_amd64.whl", hash = "sha256:ca51fcfcc5f9354c45f400059e88bc09215fb71a48d3768fb80e357f3b457e1e"}, - {file = "numpy-1.23.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8969bfd28e85c81f3f94eb4a66bc2cf1dbdc5c18efc320af34bffc54d6b1e38f"}, - {file = "numpy-1.23.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7ac231a08bb37f852849bbb387a20a57574a97cfc7b6cabb488a4fc8be176de"}, - {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf837dc63ba5c06dc8797c398db1e223a466c7ece27a1f7b5232ba3466aafe3d"}, - {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33161613d2269025873025b33e879825ec7b1d831317e68f4f2f0f84ed14c719"}, - {file = "numpy-1.23.5-cp39-cp39-win32.whl", hash = "sha256:af1da88f6bc3d2338ebbf0e22fe487821ea4d8e89053e25fa59d1d79786e7481"}, - {file = "numpy-1.23.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b7847f7e83ca37c6e627682f145856de331049013853f344f37b0c9690e3df"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:abdde9f795cf292fb9651ed48185503a2ff29be87770c3b8e2a14b0cd7aa16f8"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a909a8bae284d46bbfdefbdd4a262ba19d3bc9921b1e76126b1d21c3c34135"}, - {file = "numpy-1.23.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:01dd17cbb340bf0fc23981e52e1d18a9d4050792e8fb8363cecbf066a84b827d"}, - {file = "numpy-1.23.5.tar.gz", hash = "sha256:1b1766d6f397c18153d40015ddfc79ddb715cabadc04d2d228d4e5a8bc4ded1a"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -2484,13 +2492,13 @@ test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] [[package]] name = "orbax-checkpoint" -version = "0.5.3" +version = "0.4.4" description = "Orbax Checkpoint" optional = false python-versions = ">=3.9" files = [ - {file = "orbax_checkpoint-0.5.3-py3-none-any.whl", hash = "sha256:82acdf18acb1e294396dd583634d3b1bd005bbb81f3de650740384c465d735c3"}, - {file = "orbax_checkpoint-0.5.3.tar.gz", hash = "sha256:1572904cbbfe8513927e0d80f80b730e0ef2f680332d3c2810d8443532938b45"}, + {file = "orbax_checkpoint-0.4.4-py3-none-any.whl", hash = "sha256:e356288d7f62b30519b20ae3c0584743d6598234e4996b4c15bbbd32c13c1f04"}, + {file = "orbax_checkpoint-0.4.4.tar.gz", hash = "sha256:85ab96268b3f39e83809254cb3d55aa5a47c2279d7d3e725bd5f7c2da10a4de9"}, ] [package.dependencies] @@ -2503,7 +2511,7 @@ nest_asyncio = "*" numpy = "*" protobuf = "*" pyyaml = "*" -tensorstore = ">=0.1.51" +tensorstore = ">=0.1.35" typing_extensions = "*" [package.extras] @@ -3823,27 +3831,27 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "tensorboard" -version = "2.12.3" +version = "2.15.2" description = "TensorBoard lets you watch Tensors Flow" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tensorboard-2.12.3-py3-none-any.whl", hash = "sha256:b4a69366784bc347e02fbe7d847e01896a649ca52f8948a11005e205dcf724fb"}, + {file = "tensorboard-2.15.2-py3-none-any.whl", hash = "sha256:a6f6443728064d962caea6d34653e220e34ef8df764cb06a8212c17e1a8f0622"}, ] [package.dependencies] absl-py = ">=0.4" google-auth = ">=1.6.3,<3" -google-auth-oauthlib = ">=0.5,<1.1" +google-auth-oauthlib = ">=0.5,<2" grpcio = ">=1.48.2" markdown = ">=2.6.8" numpy = ">=1.12.0" -protobuf = ">=3.19.6" +protobuf = ">=3.19.6,<4.24.0 || >4.24.0" requests = ">=2.21.0,<3" setuptools = ">=41.0.0" +six = ">1.9" tensorboard-data-server = ">=0.7.0,<0.8.0" werkzeug = ">=1.0.1" -wheel = ">=0.26" [[package]] name = "tensorboard-data-server" @@ -3859,98 +3867,100 @@ files = [ [[package]] name = "tensorflow" -version = "2.12.0" +version = "2.15.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tensorflow-2.12.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:be4ac0dfcc7a16f6df2bc19bd322e312235ab3f7b0c7297f96c92c44bb14d2a1"}, - {file = "tensorflow-2.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5193ddb3bb5120cb445279beb08ed9e74a85a4eeb2485550d6fb707a89d9a88"}, - {file = "tensorflow-2.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357d9d2851188a8d27ee195345b4d175cad970150d1344ba9d9fcc4bf2b68336"}, - {file = "tensorflow-2.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c8001210df7202ef6267150865b0b79f834c3ca69ee3132277de8eeb994dffde"}, - {file = "tensorflow-2.12.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:91dccda42c03569d8c787190482a11ecae3b9b173aaa9166f0ab20cecc9c31f4"}, - {file = "tensorflow-2.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f81eb8adaeb558963f5d8b47dbfcc398d898f0857bf3de6b6484350236b7b5"}, - {file = "tensorflow-2.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ec4a2934ea19e92f27a9668ece43025ed5efe14b5d19be53b07692bc8a4189d"}, - {file = "tensorflow-2.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e7641e2a6e32f31ff233495478a9cc86b7c038140eab714a61eeddbbbb327c3"}, - {file = "tensorflow-2.12.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:a7194e744c5a7f3e759ecb949527b4a07718a6d1110e6e82fd4ce0c5586a7d4a"}, - {file = "tensorflow-2.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4afc2dd57435f29ebe249eb5f595d89b0e73be94922eeb7110aa6280a332837c"}, - {file = "tensorflow-2.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23850332f1f9f778d697c9dba63ca52be72cb73363e75ad358f07ddafef63c01"}, - {file = "tensorflow-2.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:e29fcf6cfd069aefb4b44f357cccbb4415a5a3d7b5b516eaf4450062fe40021e"}, - {file = "tensorflow-2.12.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:42fc2635e9420faee781a16bd393126f29cd39aa2b9d02901f24d8497bd6f958"}, - {file = "tensorflow-2.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76414355e420edb9154b4e72113eef5813ccb71701fda959afbbc1eebe3099bd"}, - {file = "tensorflow-2.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:020d6a54cb26020bdc71a7bae8ee35be05096f63e773dc517f6e87c49de62c50"}, - {file = "tensorflow-2.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:9f70a8f9ab46e5ed436850aa60d1cd40645f5c669e14bcad48915dc1f597dda2"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:9b248e0f4316b3a3c54cd1f83edfb7a761d473060c1972a8ea31a90d5de3aa72"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:eaf420d8b8ec1d4bd75859be7d7545d8e7052726eed8456fdbba63718e7e07ea"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98aab454fc73ff1900314821e5bafbf20840ada2004c8caccf4d92e0e12a628"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed601b43df9b7d9bed0203b34bcb9356efd4f671eaaac1046b7166a2afee0cf8"}, + {file = "tensorflow-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:2d88f8b71f4a8d9ab9dc7c8e42b14ca0f53d1daab0f989b8f2918907c2891f41"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1e0716622ed7af867d8b1997b00a2940f1a1587dee923ff53efa2ee506992f32"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:124930e7d4f5d74c61a5c80d642a26c22fe0c42fdd383fe9ee5803c3ac9ed4ce"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852efeb4d18beedac0120c4f2d4f4dccf4c090bb6740c5199d395ff609e85e98"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee8ec2b2c6c942ae65d25746e53cdc475e82d5fcbbb3009ce47f5963d69ebfc"}, + {file = "tensorflow-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:e05a48006930e4e9e68468e7affed3bbce8a1c7fe6df86500496ad1558804a78"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2cfcdde1ff3c01be617e99ce9783c49cb11da5796ce32a31855412bd092c0bcf"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:896bda03f722700a9918d144aee5152a75f1be5e6c5045fd0683b8318a3fc9d9"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7697b005ce48fec8b2ee8cf25bcbd138f16b5e17f99f7c01a6ea3f2429f86c6"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa865956d96b7614f247c36e4c22b1543ba5ce656fbe8e4f6266ae7a4917132"}, + {file = "tensorflow-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:01108746e1bbfcd48dfabf7f51ddca7693b91ea6821f6f62a27b5a5ebf0817c5"}, ] [package.dependencies] absl-py = ">=1.0.0" astunparse = ">=1.6.0" -flatbuffers = ">=2.0" -gast = ">=0.2.1,<=0.4.0" +flatbuffers = ">=23.5.26" +gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -jax = ">=0.3.15" -keras = ">=2.12.0,<2.13" +keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -numpy = ">=1.22,<1.24" +ml-dtypes = ">=0.2.0,<0.3.0" +numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.12,<2.13" -tensorflow-estimator = ">=2.12.0,<2.13" -tensorflow-io-gcs-filesystem = {version = ">=0.23.1", markers = "platform_machine != \"arm64\" or platform_system != \"Darwin\""} +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" +[package.extras] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] + [[package]] name = "tensorflow-cpu" -version = "2.12.0" +version = "2.15.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tensorflow_cpu-2.12.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:734ce850e2b3493041bdc071b594f0f78d35e4bfce5a7e0a98d449b20420e01d"}, - {file = "tensorflow_cpu-2.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361b19b5a64bf611beccd22de1fc04f614a8c157ac99893d9702ed24932018d6"}, - {file = "tensorflow_cpu-2.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:d5ad746bf8c87d9a9fcea4698828ba1d101a7f7bfd323a2571130374a192578b"}, - {file = "tensorflow_cpu-2.12.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b9c8f0d0658da8a5b25a4fe5ca315f86c449eb11e30d79cea49c7658be75a825"}, - {file = "tensorflow_cpu-2.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c7047552a2d759f3e65ac13e36dd24bb5fec2e6576e848287811ec44b3d62f"}, - {file = "tensorflow_cpu-2.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fdb636736f95094368bc7d26bb3b8ed93ba820cc5d95f847e00bf4a7645463d"}, - {file = "tensorflow_cpu-2.12.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5beeb99d2a1cc1383ca981513c35a4a18157e52d91a89e69c94cb7b7e411f0d8"}, - {file = "tensorflow_cpu-2.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a406f751180fe5282776e8bc84f39a2dc2b796c3ae35fbe20e4edc86ec580dd3"}, - {file = "tensorflow_cpu-2.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:b6ba926f9a56cdf0657defc6d046735e31ded383054f67c1a16ef2b0511f68d7"}, - {file = "tensorflow_cpu-2.12.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:ef4f142b6fe75fcc71ada6331ed2a15ed61b7034187049d0ef1dac482d52db78"}, - {file = "tensorflow_cpu-2.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55685b9a19c8ecb2587fb53914c045b188ed0289a2c6495e4e59d5fb082da9cc"}, - {file = "tensorflow_cpu-2.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:374b15d1cec1a62006e388062e89dd4899a121272d41ea5d3fcbcc96e2d875c9"}, + {file = "tensorflow_cpu-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:67bac86d3fce227e59fdd31d1ac45e25cfa2f2c0a3a1269b1d2acf5721fcb7af"}, + {file = "tensorflow_cpu-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f60b3d4270a507eef10d9da5ab55fdec90a4c77c664dde446709b597f0864a62"}, + {file = "tensorflow_cpu-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc52cdceb0f2e5853599e9226987ba8f260347b5b1591c8efb60b13ba2ea9fa8"}, + {file = "tensorflow_cpu-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b0b2986a6cf63053c1f63bc751b228f5478283c0aa66a58271e931ae318978ce"}, + {file = "tensorflow_cpu-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46c795177f6311c83562e05d38dc7d4618f8d3150e6902a4499b875f3f97270"}, + {file = "tensorflow_cpu-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:4487d0991e6f71bb56000f49a8ba467786b1ed7fafc7a6c0fad6d10ea46fc304"}, + {file = "tensorflow_cpu-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f02026dbb9c2d953d27d2c44de65ecf5e42f002750ae560b63484e50f869a16f"}, + {file = "tensorflow_cpu-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfd3bdc43e29a9239d05f4c116c2fb7c38dd388222d3c934138dfbcb93e5a506"}, + {file = "tensorflow_cpu-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:6900344496f0defd54c5da4aa2228bf0f332fb0a6cb5136b90b3541a6e4322d6"}, ] [package.dependencies] absl-py = ">=1.0.0" astunparse = ">=1.6.0" -flatbuffers = ">=2.0" -gast = ">=0.2.1,<=0.4.0" +flatbuffers = ">=23.5.26" +gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -jax = ">=0.3.15" -keras = ">=2.12.0,<2.13" +keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -numpy = ">=1.22,<1.24" +ml-dtypes = ">=0.2.0,<0.3.0" +numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.12,<2.13" -tensorflow-estimator = ">=2.12.0,<2.13" -tensorflow-io-gcs-filesystem = {version = ">=0.23.1", markers = "platform_machine != \"arm64\" or platform_system != \"Darwin\""} +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" +[package.extras] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] + [[package]] name = "tensorflow-datasets" version = "4.9.4" @@ -4019,12 +4029,12 @@ youtube-vis = ["pycocotools"] [[package]] name = "tensorflow-estimator" -version = "2.12.0" +version = "2.15.0" description = "TensorFlow Estimator." optional = false python-versions = ">=3.7" files = [ - {file = "tensorflow_estimator-2.12.0-py2.py3-none-any.whl", hash = "sha256:59b191bead4883822de3d63ac02ace11a83bfe6c10d64d0c4dfde75a50e60ca1"}, + {file = "tensorflow_estimator-2.15.0-py2.py3-none-any.whl", hash = "sha256:aedf21eec7fb2dc91150fc91a1ce12bc44dbb72278a08b58e79ff87c9e28f153"}, ] [[package]] @@ -4072,32 +4082,31 @@ protobuf = ">=3.7,<4" [[package]] name = "tensorstore" -version = "0.1.54" +version = "0.1.45" description = "Read and write large, multi-dimensional arrays" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "tensorstore-0.1.54-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:54dbc2d5de635ff55c4dd1e85eb8d326ed7c0c90489ab8e9dbbc93ad70f4ebf6"}, - {file = "tensorstore-0.1.54-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3d62cec4f3257e7e1d60220d6b1a604cf1e6d2f4684407669a3baa4c53b81f47"}, - {file = "tensorstore-0.1.54-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f5e0e9a81b41cba6c7462b57531855e3c0be320ae05b071b220206f04ab3b99"}, - {file = "tensorstore-0.1.54-cp310-cp310-win_amd64.whl", hash = "sha256:2ccfc236cab7d5d7c0fdd6a1e13fbe9e5aa69a8dd0c472f479dd2b8c4c66f563"}, - {file = "tensorstore-0.1.54-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:d2c032e5eb31ab0835fc21c74f5134274fe6d1f147917e1571876e4aa011d206"}, - {file = "tensorstore-0.1.54-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcf6925cc1b1793d888d6c81f3f2bafe8b78352c792a5e77cc519b4fc8fd9482"}, - {file = "tensorstore-0.1.54-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dab3fb3fca3ec23f43d502641fc7ce3f40bdb864eca63b2b10a5a6592014f00b"}, - {file = "tensorstore-0.1.54-cp311-cp311-win_amd64.whl", hash = "sha256:ba5d560d321ad353af866910bcdfb396ccd822b89d50e3275a22193dcbd6e35b"}, - {file = "tensorstore-0.1.54-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:608212a855808f0f55a3cb66a562514632023df9df26e11c8497803102e17303"}, - {file = "tensorstore-0.1.54-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02077de82f9a388badc831b8bef0242f82ce47830076130e0f947bc2db88ecc1"}, - {file = "tensorstore-0.1.54-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e19ef2c20e7139a5ba3f33b3170ff1418d2cffec01b46f16b0428b66984894e"}, - {file = "tensorstore-0.1.54-cp312-cp312-win_amd64.whl", hash = "sha256:68dc970e7f69f46d4b7bcbbcb924e0c5ad71e9a2f16481679430edb1deb65fb0"}, - {file = "tensorstore-0.1.54-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:70de04ad2177fb771f17db1a61cc1ed3295147676021cb3d63649b8a9faf2f45"}, - {file = "tensorstore-0.1.54-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:954f321049ae0fd97904b76f2b8fc49257a04fa5813c8ca4b5aafa92567e743e"}, - {file = "tensorstore-0.1.54-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ddc9c99b34afe3d64e4c2585238ace9d8a9e1818a9ffcdce356e4e20e98648"}, - {file = "tensorstore-0.1.54-cp39-cp39-win_amd64.whl", hash = "sha256:9b0501b40107c0bec29c48ce926353eee92b2b6d3b5d5bce0983c35de007eaaf"}, - {file = "tensorstore-0.1.54.tar.gz", hash = "sha256:e1a9dcb0be7c828f752375409537d4b39c658dd6c6a0873fe21a24a556ec0e2a"}, + {file = "tensorstore-0.1.45-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:2ff6e5177ba2702f348bef3edc37619aa7646e43f33d1a567ba267db455699e4"}, + {file = "tensorstore-0.1.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bc7cde6318363eb9d35fc6cacb6fcd5d7a03b0ee57bdd69249108c0164692d8"}, + {file = "tensorstore-0.1.45-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405bf40271eed5632a566cdb935beba87d9896d2f80caf75386febb529ddba45"}, + {file = "tensorstore-0.1.45-cp310-cp310-win_amd64.whl", hash = "sha256:537805adb06fff2ce9a259b81920af4c34a20f752fa28205e722b7e58a60c790"}, + {file = "tensorstore-0.1.45-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:73df4ddafe4da8e0f919ed5a75f48839013da3a99128a719fe730855252051a6"}, + {file = "tensorstore-0.1.45-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f38bba6fc0668a950b76752c743b66851c4fc7360857e8b37a4f7a4e9786760b"}, + {file = "tensorstore-0.1.45-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca212d127fcc4debb9f6b4274d584fe7724b2a349ca9444258a4127878dc3033"}, + {file = "tensorstore-0.1.45-cp311-cp311-win_amd64.whl", hash = "sha256:a8960f0e546ee493ed67b77998859f0cb94772ea31e865bf76b0c79976ac9204"}, + {file = "tensorstore-0.1.45-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:871a1fde0712a153ac44774ddace3ad841609ff5be792734d44cffb520258e92"}, + {file = "tensorstore-0.1.45-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0ce1a3d2bdbdb2c1102100ee23fa99a95b0bcdee9773862622d7da833516c8c9"}, + {file = "tensorstore-0.1.45-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8659688ec9d89cdd71046c35b3c84cf92cd8c88251e6068f8a99d6991a965028"}, + {file = "tensorstore-0.1.45-cp38-cp38-win_amd64.whl", hash = "sha256:c034fec18b6e3174d26df1cdd91ec67b720fc5de7ef0cc3804017dad8c211622"}, + {file = "tensorstore-0.1.45-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4915aee8355ee7dbc6f534d77a28c18001e19696f44f78760ec42845ac51edee"}, + {file = "tensorstore-0.1.45-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4346ab7afa0963dcaa8e64388a2bedab741c790786b577326a0b174d226c9320"}, + {file = "tensorstore-0.1.45-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05196a0464ce51867f1edd96e992fe01281de283b034d434ca6e81db319368c0"}, + {file = "tensorstore-0.1.45-cp39-cp39-win_amd64.whl", hash = "sha256:6d7b6cccb96b36356d3e61c4e89972b82123d799cc2ca50f743e30ce45d70739"}, + {file = "tensorstore-0.1.45.tar.gz", hash = "sha256:38468c621b2edf09cfdd2df4905890e83f1805c7645ec13e16df5eafabf0e5e5"}, ] [package.dependencies] -ml-dtypes = ">=0.3.1" numpy = ">=1.16.0" [[package]] @@ -4471,4 +4480,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "ebc44a0bc64bb8f90db4e98f4fc8b90bf927e5383a7ec4a2d8b67d6f7f48b4a9" +content-hash = "d88397c8574c5a6b83d69853465c74e110fcaeeccec099861841fda2ad539547" diff --git a/pyproject.toml b/pyproject.toml index 81e5df6a..af51ce33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ python = ">=3.10,<3.12" numpy = "^1.23" ase = "^3.22.1" tensorflow-cpu = "^2.12.0" -chex = "^0.1.5" +chex = "^0.1.9" optax = "^0.1.3" einops = "^0.6.0" clu = "^0.0.7" From 01c0d7285618442aa37451283d3b66cdeb73af76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 16:54:50 +0100 Subject: [PATCH 064/192] fixed install instructions and updated them --- README.md | 28 +++----------- docs/source/conf.py | 1 + docs/source/getting_started/install.rst | 49 ++++++++++++++++++------- docs/source/index.rst | 6 +-- examples/01_Model_Training.ipynb | 2 +- 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 16d78cca..c6391c93 100644 --- a/README.md +++ b/README.md @@ -12,40 +12,24 @@ It is based on [JAX](https://jax.readthedocs.io/en/latest/) and uses [JaxMD](htt ## Installation -You can install [Poetry](https://python-poetry.org/) via +Apax is available on PyPI with a CPU version of JAX. ```bash -curl -sSL https://install.python-poetry.org | python3 - +pip install apax ``` -Now you can install apax in your project by running +For more detailed instructions, please refer to the [documentation](https://apax.readthedocs.io/en/latest/). -```bash -poetry add git+https://github.com/apax-hub/apax.git -``` - -As a developer, you can clone the repository and install it via - -```bash -git clone https://github.com/apax-hub/apax.git -cd -poetry install -``` ### CUDA Support -Note that the above only installs the CPU version. -If you want to enable GPU support, please overwrite the jaxlib version: - -```bash -pip install --upgrade pip -``` +If you want to enable GPU support (only on Linux), please overwrite the jaxlib version: -CUDA 12 installation. Wheels only available on linux. +CUDA 12: ```bash pip install --upgrade "jax[cuda12_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html ``` -CUDA 11 installation. Wheels only available on linux. +CUDA 11: ```bash pip install --upgrade "jax[cuda11_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html ``` diff --git a/docs/source/conf.py b/docs/source/conf.py index 3e5717f9..0c822222 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,6 +25,7 @@ "sphinx.ext.napoleon", "sphinx.ext.autosummary", "sphinx.ext.mathjax", + "sphinx_copybutton", "nbsphinx", "nbsphinx_link", "sphinx.ext.viewcode", diff --git a/docs/source/getting_started/install.rst b/docs/source/getting_started/install.rst index b8a7f611..c3126d91 100644 --- a/docs/source/getting_started/install.rst +++ b/docs/source/getting_started/install.rst @@ -1,22 +1,40 @@ +============ Installation ============ -If you do not have Poetry_ installed already, you can obtain it by running +From PyPI (soon) .. highlight:: bash .. code-block:: bash - curl -sSL https://install.python-poetry.org | python3 - + pip install apax + +From GitHub +----------- -Now you can add apax to your project by running +If you would like to have a pre-release version, +you can install Apax from GitHub directly .. highlight:: bash .. code-block:: bash - poetry add git+https://github.com/apax-hub/apax.git + pip install git+https://github.com/apax-hub/apax.git -As a developer, you first need to clone the repository and install it via + +For Developers +-------------- + +As a developer, you first need to install Poetry_. +You can obtain it by running + +.. highlight:: bash +.. code-block:: bash + + curl -sSL https://install.python-poetry.org | python3 - + + +You can then clone and install the project. .. highlight:: bash .. code-block:: bash @@ -25,22 +43,25 @@ As a developer, you first need to clone the repository and install it via cd poetry install -CUDA Support -============ -Note that the above only installs the CPU version. + +CUDA Support (Linux only) +========================= + +Note that all of the above only install the CPU version. If you want to enable GPU support, please overwrite the jaxlib version: +CUDA 12: + .. highlight:: bash .. code-block:: bash - pip install --upgrade pip - - # CUDA 12 installation - # Note: wheels only available on linux. pip install --upgrade "jax[cuda12_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html - # CUDA 11 installation - # Note: wheels only available on linux. +CUDA 11: + +.. highlight:: bash +.. code-block:: bash + pip install --upgrade "jax[cuda11_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html diff --git a/docs/source/index.rst b/docs/source/index.rst index 58d34fe1..d58cd9ba 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,10 +1,10 @@ =================================================== -apax: Atomistic learned Potentials in JAX! +Apax: Atomistic learned Potentials in JAX! =================================================== -`apax` is a high-performance, extendable package for training of and inference with atomistic neural networks., most prominently the Gaussian Moment Neural Network. -It is based on [JAX](https://jax.readthedocs.io/en/latest/) and uses [JaxMD](https://github.com/jax-md/jax-md) as a molecular dynamics engine. +`Apax` is a high-performance, extendable package for training of and inference with atomistic neural networks., most prominently the Gaussian Moment Neural Network. +It is based on `JAX `_ and uses `JaxMD `_ as a molecular dynamics engine. .. toctree:: :hidden: diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index dd60fa86..f5621dda 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -43,7 +43,7 @@ "In the following we are going to use a minimal input file. To see a complete list and explanation of all parameters, consult the documentation page LINK.\n", "For more information on the CLI, simply run `apax -h`.\n", "\n", - "apax template train --minimal\n", + "`apax template train --minimal`\n", "\n", "Open the resulting `config_minimal.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training.\n", From 2e8d02832fe7aca2249d61ade017692a1288c773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 1 Mar 2024 17:10:38 +0100 Subject: [PATCH 065/192] header format --- docs/source/getting_started/install.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/getting_started/install.rst b/docs/source/getting_started/install.rst index c3126d91..86884062 100644 --- a/docs/source/getting_started/install.rst +++ b/docs/source/getting_started/install.rst @@ -44,6 +44,7 @@ You can then clone and install the project. poetry install +========================= CUDA Support (Linux only) ========================= From 4b0e11fce2e910ba8b98f80c9638d376e49eaa08 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 17:43:46 +0100 Subject: [PATCH 066/192] dataset download in untils --- apax/utils/__init__.pyi | 4 +-- apax/utils/datasets.py | 77 +++++++++++++++++++++++++++++++++++++++++ apax/utils/helpers.py | 12 +++++++ tests/conftest.py | 38 +++----------------- 4 files changed, 96 insertions(+), 35 deletions(-) create mode 100644 apax/utils/datasets.py diff --git a/apax/utils/__init__.pyi b/apax/utils/__init__.pyi index e145989b..289ae4ae 100644 --- a/apax/utils/__init__.pyi +++ b/apax/utils/__init__.pyi @@ -1,3 +1,3 @@ -from . import convert, data, jax_md_reduced, math, random +from . import convert, data, jax_md_reduced, math, random, datasets -__all__ = ["convert", "data", "math", "random", "jax_md_reduced"] +__all__ = ["convert", "data", "math", "random", "jax_md_reduced", datasets] diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py new file mode 100644 index 00000000..3af78425 --- /dev/null +++ b/apax/utils/datasets.py @@ -0,0 +1,77 @@ +import os +import urllib +import zipfile + +def download_md22_stachyose(data_path): + url = "http://www.quantum-machine.org/gdml/repo/static/md22_stachyose.zip" + file_path = data_path / "md22_stachyose.zip" + + os.makedirs(data_path, exist_ok=True) + urllib.request.urlretrieve(url, file_path) + + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(data_path) + + file_path = modify_xyz_file( + file_path.with_suffix(".xyz"), target_string="Energy", replacement_string="energy" + ) + + return file_path + + +def download_md17_benzene_DFT(data_path): + url = "http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip" + file_path = data_path / "benzene2018_dft.zip" + + os.makedirs(data_path, exist_ok=True) + urllib.request.urlretrieve(url, file_path) + + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(data_path) + + new_file_path = data_path / "benzene.xyz" + os.remove(file_path) + + return new_file_path + + +def download_md17_benzene_CCSDT(data_path): + url = "http://www.quantum-machine.org/gdml/data/xyz/benzene_ccsd_t.zip" + file_path = data_path / "benzene_ccsdt.zip" + + os.makedirs(data_path, exist_ok=True) + urllib.request.urlretrieve(url, file_path) + + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(data_path) + + train_file_path = data_path / "benzene_ccsd_t-train.xyz" + os.remove(file_path) + + return train_file_path + + +def modify_xyz_file(file_path, target_string, replacement_string): + new_file_path = file_path.with_name(file_path.stem + "_mod" + file_path.suffix) + + with open(file_path, "r") as input_file, open(new_file_path, "w") as output_file: + for line in input_file: + # Replace all occurrences of the target string with the replacement string + modified_line = line.replace(target_string, replacement_string) + output_file.write(modified_line) + return new_file_path + + +def mod_md17(file_path): + new_file_path = file_path.with_name(file_path.stem + "_mod" + file_path.suffix) + with open(file_path, "r") as input_file, open(new_file_path, "w") as output_file: + for line in input_file: + if line.startswith("-"): + modified_line = f"Properties=species:S:1:pos:R:3:forces:R:3 energy={line}" + else: + modified_line = line + output_file.write(modified_line) + + os.remove(file_path) + + return new_file_path \ No newline at end of file diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 0acb2378..91d32fe3 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -1,3 +1,6 @@ +import yaml + + def setup_ase(): """Add uncertainty keys to ASE all properties. from https://github.com/zincware/IPSuite/blob/main/ipsuite/utils/helpers.py#L10 @@ -7,3 +10,12 @@ def setup_ase(): for val in ["forces_uncertainty", "energy_uncertainty", "stress_uncertainty"]: if val not in all_properties: all_properties.append(val) + + +def mod_config(config_path, updated_config): + with open(config_path.as_posix(), "r") as stream: + config_dict = yaml.safe_load(stream) + + for key, new_value in updated_config.items(): + config_dict[key].update(new_value) + return config_dict \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 599817ce..8376e122 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,4 @@ import os -import urllib -import zipfile from typing import List import jax @@ -15,7 +13,8 @@ from apax.model.builder import ModelBuilder from apax.train.run import run from apax.utils.random import seed_py_np_tf - +from apax.utils.datasets import download_md22_stachyose +from apax.utils.helpers import mod_config @pytest.fixture(autouse=True) def set_radom_seeds(): @@ -114,33 +113,10 @@ def tmp_data_path(tmp_path_factory): @pytest.fixture(scope="session") def get_md22_stachyose(tmp_data_path): - url = "http://www.quantum-machine.org/gdml/repo/static/md22_stachyose.zip" - file_path = tmp_data_path / "md22_stachyose.zip" - - os.makedirs(tmp_data_path, exist_ok=True) - urllib.request.urlretrieve(url, file_path) - - with zipfile.ZipFile(file_path, "r") as zip_ref: - zip_ref.extractall(tmp_data_path) - - file_path = modify_xyz_file( - file_path.with_suffix(".xyz"), target_string="Energy", replacement_string="energy" - ) - + file_path = download_md22_stachyose(tmp_data_path) return file_path -def modify_xyz_file(file_path, target_string, replacement_string): - new_file_path = file_path.with_name(file_path.stem + "_mod" + file_path.suffix) - - with open(file_path, "r") as input_file, open(new_file_path, "w") as output_file: - for line in input_file: - # Replace all occurrences of the target string with the replacement string - modified_line = line.replace(target_string, replacement_string) - output_file.write(modified_line) - return new_file_path - - @pytest.fixture() def get_sample_input(): positions = np.array([ @@ -179,9 +155,5 @@ def load_and_dump_config(config_path, dump_path): def load_config_and_run_training(config_path, updated_config): - with open(config_path.as_posix(), "r") as stream: - config_dict = yaml.safe_load(stream) - - for key, new_value in updated_config.items(): - config_dict[key].update(new_value) - run(config_dict) + config_dict = mod_config(config_path, updated_config) + run(config_dict) \ No newline at end of file From 95ee47b441a7b4997e2bc070c4eeb13c9765259b Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 17:44:04 +0100 Subject: [PATCH 067/192] example 01 update --- examples/01_Model_Training.ipynb | 132 ++++++++++++++++++++++++---- examples/03_Transfer_learning.ipynb | 21 +++++ 2 files changed, 134 insertions(+), 19 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index dd60fa86..b91df92f 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -11,24 +11,23 @@ "\n", "## Acquiring a dataset\n", "\n", - "# TODO tmpdir\n", - "\n", - "```bash\n", - "mkdir project\n", - "cd project\n", - "```\n", - "You can obtain the benzene dataset either by running the following command or manually from this website.\n", - "\n", - "`curl ... ...`\n", - "\n", - "apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc)." + "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mop_md17` function in order to be readable." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 1, "metadata": {}, + "outputs": [], "source": [ - "TODO Dataset splitting" + "from pathlib import Path\n", + "from apax.utils.datasets import download_md17_benzene_DFT, mod_md17\n", + "\n", + "data_path = Path(\"project\")\n", + "\n", + "file_path = download_md17_benzene_DFT(data_path)\n", + "file_path = mod_md17(file_path)\n", + "\n" ] }, { @@ -41,12 +40,99 @@ "In order to get users quickly up and running, our command line interface provides an easy way to generate input templates.\n", "The provided templates come in in two levels of verbosity: minimal and full.\n", "In the following we are going to use a minimal input file. To see a complete list and explanation of all parameters, consult the documentation page LINK.\n", - "For more information on the CLI, simply run `apax -h`.\n", + "For more information on the CLI, simply run `apax -h`." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mapax [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-version\u001b[0m \u001b[1;32m-V\u001b[0m \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m Install completion for the current shell. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m Show completion for the current shell, to \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m copy it or customize the installation. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m \u001b[1;32m-h\u001b[0m Show this message and exit. \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mdocs \u001b[0m\u001b[1;36m \u001b[0m Opens the documentation website in your browser. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36meval \u001b[0m\u001b[1;36m \u001b[0m Starts performing the evaluation of the test dataset with \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvalidate \u001b[0m\u001b[1;36m \u001b[0m Validate training or MD config files. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvisualize\u001b[0m\u001b[1;36m \u001b[0m Visualize a model based on a configuration file. A CO molecule is \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m taken as sample input (influences number of atoms, number of \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m species is set to 10). \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\n" + ] + } + ], + "source": [ + "!apax -h" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There is already a config file in the working directory.\n" + ] + } + ], + "source": [ + "!apax template train" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from apax.utils.helpers import mod_config\n", "\n", - "apax template train --minimal\n", + "config_path = Path(\"config.yaml\")\n", "\n", - "Open the resulting `config_minimal.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", - "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training.\n", + "config_updates = {\n", + " \"data\": {\n", + " \"energy_unit\": \"kcal/mol\",\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", + "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", "\n", "The filled in configuration file should look similar to this one.\n", "\n", @@ -105,7 +191,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -153,8 +239,16 @@ "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.11.5" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" } }, "nbformat": 4, diff --git a/examples/03_Transfer_learning.ipynb b/examples/03_Transfer_learning.ipynb index 7d3cc3a2..0412479f 100644 --- a/examples/03_Transfer_learning.ipynb +++ b/examples/03_Transfer_learning.ipynb @@ -45,6 +45,27 @@ "We can now fine tune the model by running\n", "`apax train config.yaml`" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "from apax.utils.datasets import download_md17_benzene_CCSDT, mod_md17\n", + "import os\n", + "\n", + "data_path = Path(\"project\")\n", + "file_path = download_md17_benzene_CCSDT(data_path)\n", + "os.remove(data_path / \"benzene_ccsd_t-test.xyz\")\n", + "\n", + "file_path = mod_md17(file_path)" + ] } ], "metadata": { From 2ff66dbc8e316d00ab459838c38c47d6bb62af7f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:47:50 +0000 Subject: [PATCH 068/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/datasets.py | 2 +- apax/utils/helpers.py | 2 +- tests/conftest.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 3af78425..3b6aa7d7 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -74,4 +74,4 @@ def mod_md17(file_path): os.remove(file_path) - return new_file_path \ No newline at end of file + return new_file_path diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 91d32fe3..398ff899 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -18,4 +18,4 @@ def mod_config(config_path, updated_config): for key, new_value in updated_config.items(): config_dict[key].update(new_value) - return config_dict \ No newline at end of file + return config_dict diff --git a/tests/conftest.py b/tests/conftest.py index 8376e122..184d2418 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -156,4 +156,4 @@ def load_and_dump_config(config_path, dump_path): def load_config_and_run_training(config_path, updated_config): config_dict = mod_config(config_path, updated_config) - run(config_dict) \ No newline at end of file + run(config_dict) From 32f13870dc3a88fc85433bd3d5342f63d36ff3bd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:48:41 +0000 Subject: [PATCH 069/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/datasets.py | 1 + tests/conftest.py | 1 + 2 files changed, 2 insertions(+) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 3b6aa7d7..b6935037 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -2,6 +2,7 @@ import urllib import zipfile + def download_md22_stachyose(data_path): url = "http://www.quantum-machine.org/gdml/repo/static/md22_stachyose.zip" file_path = data_path / "md22_stachyose.zip" diff --git a/tests/conftest.py b/tests/conftest.py index 184d2418..ad74cc70 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,6 +16,7 @@ from apax.utils.datasets import download_md22_stachyose from apax.utils.helpers import mod_config + @pytest.fixture(autouse=True) def set_radom_seeds(): seed_py_np_tf() From 1a30e4257eb03748c3bb3a3a8125503277ae191d Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 21:32:32 +0100 Subject: [PATCH 070/192] mod_config bug fix --- apax/utils/helpers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 91d32fe3..1ffd89d6 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -17,5 +17,8 @@ def mod_config(config_path, updated_config): config_dict = yaml.safe_load(stream) for key, new_value in updated_config.items(): - config_dict[key].update(new_value) + if isinstance(config_dict[key], dict): + config_dict[key].update(new_value) + else: + config_dict[key] = new_value return config_dict \ No newline at end of file From ef8a9225d95e5d095be6a04a974192b02b38642b Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 21:32:55 +0100 Subject: [PATCH 071/192] Model training example --- examples/01_Model_Training.ipynb | 350 +++++++++++++++++++++++++++---- 1 file changed, 305 insertions(+), 45 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index b91df92f..ce166874 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -45,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -93,20 +93,10 @@ ] }, { - "cell_type": "code", - "execution_count": 3, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "There is already a config file in the working directory.\n" - ] - } - ], "source": [ - "!apax template train" + "The following command create a minimal configuration file in the working directory." ] }, { @@ -115,16 +105,7 @@ "metadata": {}, "outputs": [], "source": [ - "from apax.utils.helpers import mod_config\n", - "\n", - "config_path = Path(\"config.yaml\")\n", - "\n", - "config_updates = {\n", - " \"data\": {\n", - " \"energy_unit\": \"kcal/mol\",\n", - " }\n", - "}\n", - "config_dict = mod_config(config_path, config_updates)" + "!apax template train" ] }, { @@ -132,31 +113,120 @@ "metadata": {}, "source": [ "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", - "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", + "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Further, the units of the labels have to be specified. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", "\n", "The filled in configuration file should look similar to this one.\n", "\n", "```yaml\n", + "epoch: 1000\n", "data:\n", " data_path: md17.extexyz\n", " epochs: 1000\n", " n_train: 1000\n", + " energy_unit: kcal/mol\n", + " pos_unit: Ang\n", " ....\n", - "```" + "```\n", + "\n", + "It also can be modefied with the utils function `mod_config` provided by Apax.\n" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 5, "metadata": {}, + "outputs": [], "source": [ - "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n", + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 10,\n", + " \"data\": {\n", + " \"experiment\": \"benzene_dft_cli\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", "\n", - "`apax validate train config_minimal.yaml`\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", + "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "config.yaml is a valid training config.\n" + ] + } + ], + "source": [ + "!apax validate train config.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file.\n", - "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:\n", + "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "config_updates = {\n", + " \"n_epochs\": -1000,\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", "\n", - "`PYDANTIC ERROR`" + "with open(\"error_config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 validation error for Config\n", + "n_epochs\n", + " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", + " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", + "\u001b[31mConfiguration Invalid!\u001b[0m\n" + ] + } + ], + "source": [ + "!apax validate train error_config.yaml" ] }, { @@ -165,9 +235,46 @@ "source": [ "## Training\n", "\n", - "Model training can be started by running\n", + "Model training can be started by running" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 21:25:29 | Initializing Callbacks\n", + "INFO | 21:25:29 | Initializing Loss Function\n", + "INFO | 21:25:29 | Initializing Metrics\n", + "INFO | 21:25:29 | Running Input Pipeline\n", + "INFO | 21:25:29 | Read data file project/benzene_mod.xyz\n", + "INFO | 21:25:29 | Loading data from project/benzene_mod.xyz\n", + "INFO | 21:25:39 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13445.14it/s]\n", + "INFO | 21:25:39 | Computing per element energy regression.\n", + "INFO | 21:25:45 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11969.02it/s]\n", + "INFO | 21:25:46 | Initializing Model\n", + "INFO | 21:25:46 | initializing 1 models\n", + "INFO | 21:25:53 | Initializing Optimizer\n", + "INFO | 21:25:53 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.87s/it, val_loss=0.63]\n" + ] + } + ], + "source": [ + "!apax train config.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "`apax train config.yaml`\n", "\n", "During training, apax displays a progress bar to keep track of the validation loss.\n", "This progress bar is optional however and can be turned off in the config. LINK\n", @@ -179,38 +286,160 @@ " - CSV\n", "```\n", "\n", - "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint." + "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint.\n", + "\n", + "Furthermore, an Apax trianing can easily be started within a scriped." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 10, "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11786.22it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10499.15it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:44<00:00, 2.24s/it, val_loss=0.31]\n" + ] + } + ], "source": [ - "TODO plot train val loss" + "from apax.train.run import run\n", + "\n", + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"experiment\": \"benzene_dft_script\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " }\n", + "}\n", + "\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "run(config_dict)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWD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Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAAWItieIxIS6IzHAAAAJCksWPH6vPPP7c6jKhzBmeG+3wWRwIAANA+tejM8D/96U/KzMxsybuIG4xJAQAAAALOPfdc3XXXXVq7dq2GDBkip9MZdv35559vUWRHxk1nOAAAgKWaXQx/+umnm33QW265RZJ0+eWXH35E7VSwGF5KMRwAAADt3LXXXitJeuihhxpdZxiGfG20s9plpxgOAABgpWYXw5988slm7WcYRqgYjuajMxwAAAAI8Pvjs1gcnBnu9ZkWRwIAANA+NbsYXlBQ0JJxtHvBYnhxJcVwAAAAIB4Fi+E1dIYDAABYokVnhqP5WEATAAAA7dnTTz+t6667TgkJCT86orGtfhI1NCbFRzEcAADAChEXw7dv365//etf2rp1qzweT9h1M2bMOOLA2puU4Mzwaq/8flM2m2FxRAAAAEDrefLJJzV+/HglJCT84IjGtjyW0RlaQLNtzjwHAABo6yIqhi9dulTnn3+++vTpo3Xr1umYY47Rli1bZJqmjj322GjH2C4Ex6SYplRWUxv6GQAAAGgPGo5ljNcRjSygCQAAYC1bJDeaPHmy7rzzTq1Zs0YJCQl67bXXtG3bNp166qm66KKLoh1ju+B22JXgDJyOUkalAAAAAHHH7WBMCgAAgJUi6gz/9ttvNX/+/MABHA5VVVWpY8eOeuihh3TBBRfo+uuvj2qQ7UVqolPV3hoVV3qVk251NAAAAIB14nEsY3ABTW+taXEkAAAA7VNExfAOHTqEEtJu3bpp8+bNGjx4sCRp79690YuunUlLdKmotIZFNAEAANCuxetYRhed4QAAAJaKaEzKCSecoI8++kiSdM455+iOO+7Q7373O1199dU64YQTohpgexKcE04xHAAAAO1ZvI5lZGY4AACAtSLqDJ8xY4bKy8slSQ8++KDKy8u1cOFC9e/fv81+ZDEWpFAMBwAAAOJ2LKOzrhheQzEcAADAEhEVwx999FFdccUVkgIjU2bPnh3VoNorOsMBAACA+B3LGBqTUuuzOBIAAID2KaIxKXv27NHZZ5+tnJwc3XXXXVq9enW042qXgsXw4irPj+wJAAAAxK94HcvoZmY4AACApSIqhr/++uvatWuXpkyZos8++0zHHnusBg8erEcffVRbtmyJcojtR1pSoBheSmc4AAAA2rEZM2Zo9OjRkgJjGc844wwtXLhQvXr10osvvmhxdJGr7wynGA4AAGCFiMakSFKnTp103XXX6brrrtP27ds1f/58zZkzR1OnTlVtbW00Y2w3GJMCAACA9s7n82n79u0aOnSopPgayxhcQNNvSj6/KbvNsDgiAACA9iWizvCGvF6vPv/8c61cuVJbtmxRZmZmNOJqlyiGAwAAoL2z2+0666yzdODAAatDibpgZ7hEdzgAAIAVIi6Gf/DBB7r22muVmZmpq666SikpKXrjjTe0ffv2aMbXrlAMBwAAAKRjjjlG3333ndVhRJ3TTjEcAADAShGNSenevbv279+vs88+W3/+85913nnnye12Rzu2dicluIBmJcVwAAAAtF+PPPKI7rzzTj388MMaOXKkOnToEHZ9SkqKRZEdGae9fixKjc8nyWldMAAAAO1QRMXwBx54QBdddJHS0tKiHE77FlxAk85wAAAAtGfnnHOOJOn888+XYdQXkE3TlGEY8vl8VoV2RAzDkMthk6fWT2c4AACABSIak3LttddGtRA+a9Ys9erVSwkJCRo9erQ+/fTTQ+47d+5cGYYRdklISAjbxzRNTZ06Vd26dVNiYqJyc3O1cePGqMXbUoJjUsqqa+XzmxZHAwAAAFjjL3/5i9577z198MEHev/990OXpUuXas6cOVaHd0TcdaNSKIYDAAC0vog6w6Np4cKFysvL0+zZszV69GjNnDlTY8eO1fr169W1a9cmb5OSkqL169eHfm7YLSJJjz/+uJ5++mnNmzdPvXv31pQpUzR27FitXbu2UeE8lgSL4ZJUVu1VWpLLwmgAAAAAa1x99dXatWtXo9cD+/btU25uriZOnGhRZEfO5bBJNZLXR/MLAABAa4t4Ac1omTFjhq699lpNmjRJgwYN0uzZs5WUlPSDHR+GYSgrKyt0yczMDF1nmqZmzpyp3/72t7rgggs0dOhQvfTSS9q5c6cWLVrUCo8ock67TUkuuyRGpQAAAKD9Co5DOVh5eXlMN7c0h8tBZzgAAIBVLO0M93g8WrVqlSZPnhzaZrPZlJubqxUrVhzyduXl5erZs6f8fr+OPfZYPfrooxo8eLAkqaCgQIWFhcrNzQ3tn5qaqtGjR2vFihW69NJLGx2vpqZGNTU1oZ9LS0uj8fAikproVKXHp+JKr3p2tiwMAAAAoNXl5eVJCjS/TJkyRUlJSaHrfD6fVq5cqeHDhzfrWLGU4zfkDI5JaaNzzwEAANoyS4vhe/fulc/nC+vslqTMzEytW7euydsMGDBAc+bM0dChQ1VSUqI//OEPOvHEE/XNN9/oqKOOUmFhYegYBx8zeN3Bpk2bpgcffDAKj+jIpSY6taukms5wAAAAtDtffvmlpEBn+Jo1a+Ry1Y8NdLlcGjZsmO68885mHSuWcvyGgp3hNXSGAwAAtDrLZ4YfrjFjxmjMmDGhn0888UQdffTR+tOf/qSHH344omNOnjw51IUiBbpGcnJyjjjWSATnhlMMBwAAQHvzwQcfSJImTZqkp556SikpKREfK5Zy/IZcLKAJAABgGUuL4RkZGbLb7SoqKgrbXlRUpKysrGYdw+l0asSIEdq0aZMkhW5XVFSkbt26hR3zUB+pdLvdcrvdETyC6KMYDgAAgPbuL3/5yxEfI5Zy/IaYGQ4AAGAdSxfQdLlcGjlypJYuXRra5vf7tXTp0rDu7x/i8/m0Zs2aUOG7d+/eysrKCjtmaWmpVq5c2exjWoliOAAAABC/gsVwr8+0OBIAAID2x/IxKXl5eZo4caJGjRql448/XjNnzlRFRYUmTZokSZowYYK6d++uadOmSZIeeughnXDCCerXr5+Ki4v1+9//Xt9//72uueYaSYHFdm677TY98sgj6t+/v3r37q0pU6YoOztbF154oVUPs9kohgMAAADxy+1gAU0AAACrWF4Mv+SSS7Rnzx5NnTpVhYWFGj58uBYvXhxaAHPr1q2y2eob2A8cOKBrr71WhYWF6tSpk0aOHKmPP/5YgwYNCu1z9913q6KiQtddd52Ki4t18skna/HixUpISGj1x3e40pLqiuGVFMMBAACAeMPMcAAAAOsYpmny+byDlJaWKjU1VSUlJUe0aE8k/rpii6a8/o3OHpyl2VeObNX7BgAAiHdW5nmwVqyc+1//dZUWf1Oohy8YrCvH9LIsDgAAgHhxOHmepTPD0VgKY1IAAACAuBWcGV5DZzgAAECroxgeY5gZDgAAAMQvV2hmOMVwAACA1kYxPMZQDAcAAADiV7AY7q1lWiUAAEBroxgeY9KSXJIohgMAAADxKLSAps9ncSQAAADtD8XwGBPsDC+vqVUtH50EAAAA4oo7OCaFmeEAAACtjmJ4jElJcIS+L62utTASAAAAANHmtFMMBwAAsArF8BjjsNvU0R0oiDMqBQAAAIgvLKAJAABgHYrhMSg4KqW40mNxJAAAAACiKVgMr6EzHAAAoNVRDI9BwWI4neEAAABAfHExJgUAAMAyFMNjEMVwAAAAID4FO8O9jEkBAABodRTDY1CwGF5KMRwAAACIK6GZ4XSGAwAAtDqK4TGIznAAAAAgPoXGpNAZDgAA0Ooohseg1KTgApoUwwEAAIB4kuAMvASr9PgsjgQAAKD9oRgeg+gMBwAAAOJTdlqiJGnb/iqLIwEAAGh/KIbHIIrhAAAAQHzqldFBkrS3vEblNbUWRwMAANC+UAyPQRTDAQAAgPiUkuBU5w4uSdKWvRUWRwMAANC+UAyPQRTDAQAAgPjVs3OSJGnLPorhAAAArYlieAyiGA4AAADEr+CoFDrDAQAAWhfF8BiUlkQxHAAAAIhXvTvXFcP3VVocCQAAQPtCMTwGBTvDKz0+eX1+i6MBAAAAEE10hgMAAFiDYngMSk5whr6nOxwAAACIL71CneEUwwEAAFoTxfAYZLcZSk5wSKIYDgAAAMSbXhmBBTT3lntUVk2+DwAA0Foohseo4KiU4kqSYwAAACCeJCc4ldHRJUnaspe54QAAAK2FYniMCi6iWUpnOAAAABB3GJUCAADQ+iiGx6hgZzhjUgAAAID4wyKaAAAArY9ieIyiGA4AAADEr16dA3PDC+gMBwAAaDUUw2MUxXAAAAAgftEZDgAA0PoohseoFBbQBAAAAOJWcGb49/tYQBMAAKC1UAyPUXSGAwAAAPEr2Bm+r8Kj0mpyfgAAgNZAMTxGpSW6JFEMBwAAAOJRR7dDXZLdkhiVAgAA0Fpiohg+a9Ys9erVSwkJCRo9erQ+/fTTQ+77/PPP65RTTlGnTp3UqVMn5ebmNtr/qquukmEYYZezzz67pR9GVAU7w0sphgMAAABxKbSIJsVwAACAVmF5MXzhwoXKy8vT/fffry+++ELDhg3T2LFjtXv37ib3X7ZsmS677DJ98MEHWrFihXJycnTWWWdpx44dYfudffbZ2rVrV+gyf/781ng4UcOYFAAAACC+BeeGb9nL3HAAAIDWYHkxfMaMGbr22ms1adIkDRo0SLNnz1ZSUpLmzJnT5P5///vfdcMNN2j48OEaOHCgXnjhBfn9fi1dujRsP7fbraysrNClU6dOrfFwoiZYDC+u8lgcCQAAAICWEJwb/v0+OsMBAABag6XFcI/Ho1WrVik3Nze0zWazKTc3VytWrGjWMSorK+X1epWenh62fdmyZeratasGDBig66+/Xvv27TvkMWpqalRaWhp2sRqd4QAAAEDkYjHHP1jvumJ4AcVwAACAVmFpMXzv3r3y+XzKzMwM256ZmanCwsJmHeM3v/mNsrOzwwrqZ599tl566SUtXbpU06dP1/LlyzVu3Dj5fL4mjzFt2jSlpqaGLjk5OZE/qChJTQoUw6u9ftXUNh03AAAAgKbFYo5/sJ51M8NZQBMAAKB1WD4m5Ug89thjWrBggf75z38qISEhtP3SSy/V+eefryFDhujCCy/UG2+8oc8++0zLli1r8jiTJ09WSUlJ6LJt27ZWegSHlux2yDAC39MdDgAAAByeWMzxDxacGX6g0quSSnJ+AACAlmZpMTwjI0N2u11FRUVh24uKipSVlfWDt/3DH/6gxx57TO+++66GDh36g/v26dNHGRkZ2rRpU5PXu91upaSkhF2sZrMZSkkIdIeXUgwHAAAADkss5vgH6+B2qGuyW5K0hVEpAAAALc7SYrjL5dLIkSPDFr8MLoY5ZsyYQ97u8ccf18MPP6zFixdr1KhRP3o/27dv1759+9StW7eoxN1aQoto0iUCAAAAxKXgIpoUwwEAAFqe5WNS8vLy9Pzzz2vevHn69ttvdf3116uiokKTJk2SJE2YMEGTJ08O7T99+nRNmTJFc+bMUa9evVRYWKjCwkKVl5dLksrLy3XXXXfpk08+0ZYtW7R06VJdcMEF6tevn8aOHWvJY4wUi2gCAAAA8a133aiUAuaGAwAAtDiH1QFccskl2rNnj6ZOnarCwkINHz5cixcvDi2quXXrVtls9TX75557Th6PR7/85S/DjnP//ffrgQcekN1u11dffaV58+apuLhY2dnZOuuss/Twww/L7Xa36mM7UmlJFMMBAACAeNYzg0U0AQAAWovlxXBJuummm3TTTTc1ed3Bi15u2bLlB4+VmJiod955J0qRWSuFznAAAAAgroU6w/dVWhwJAABA/LN8TAoOjTEpAAAAQHwLzgz/npnhAAAALY5ieAxjAU0AAAAgvvWq6wwvrvSquNJjcTQAAADxjWJ4DAsWw0vpDAcAAADiUqLLrqyUBEksogkAANDSKIbHsDTGpAAAAABxr2fnukU0GZUCAADQoiiGxzBmhgMAAADxr3fd3PAte1lEEwAAoCVRDI9hwWJ4UVm1TNO0OBoAAAAALSG4iCad4QAAAC2LYngMG5SdIrfDpm37q/RpwX6rwwEAAADQAoKLaG5hZjgAAECLohgew9KSXPrFyKMkSS98VGBxNAAAAABaQnBMSsHeCj4RCgAA0IIohse4q0/qLUl679siOkUAAACAONQjPbCAZml1rQ5Usl4QAABAS6EYHuP6de2o0wd0kWlKf/kv3eEAAABAvEl02dUtNUESc8MBAABaEsXwNuBXJ/eRJL26artK6BQBAAAA4g5zwwEAAFoexfA24KR+nTUwK1mVHp/mf7bV6nAAAAAARFmvurnhm3aXWxwJAABA/KIY3gYYhqGrTw7MDp/38RZ5fX6LIwIAAAAQTSN6pEmS/vrJ9yoqrbY2GAAAgDhFMbyNOH9YtjI6urSrpFpvf11odTgAAAAAoujnI7pr6FGpKquu1W8XfS3TNK0OCQAAIO5QDG8jEpx2XXlCL0nSi//5juQYAAAAiCMOu02P/3KonHZDS9YW6Y2vdlkdEgAAQNyhGN6GjD+hh1wOm1ZvL9Gq7w9YHQ4AAACAKBqYlaIbTusnSXrgX99of4XH4ogAAADiC8XwNiSjo1s/H9FdkvTCfwosjgYAAABAtN14ej8NyEzWvgqPHvz3N1aHAwAAEFcohrcxwYU0311bqG37Ky2OBgAAAEA0uRyBcSk2Q3o9f6eWfltkdUgAAABxg2J4G/OTzGSd0j9DfjPw0ckqj8/qkAAAAABE0bCcNF1zSh9J0n3//Fql1V6LIwIAAIgPFMPboFvO6C+HzdDSdbt10Z8+1s7iKqtDAgAAABBFt+f+RL06J6mwtFrT3vrW6nAAAADiAsXwNui4Xun6+zWjld7Bpa93lOr8Z/+rVd/vtzosAAAAAFGS6LJr+i+GSpLmf7pNv3tzrfaV11gcFQAAQNtGMbyNGt2ns16/8SQNzErW3vIaXfrnT/TKZ9usDgsAAABAlIzu01nX1K0Z9Px/CnTK4x/o8cXrVFzpsTgyAACAtolieBuWk56kf9xwosYdkyWvz9Tdr32lB/71jcqYKQgAAADEhfvOPVp/ueo4DemeqkqPT39ctlknT/9AM5ZsUEkVeT8AAMDhMEzTNK0OItaUlpYqNTVVJSUlSklJsTqcH+X3m3rm/U168r0NkiSHzdBxvdJ1xtFddfrAruqT0UGGYYT2r/b6tP1Apb7fV6nURKdG9uwUdj0AAEC8amt5HqKnrZ970zS1ZG2RZizZoHWFZZIkl8OmwdkpGnZUmoblpGroUWnq3bmDbDZyewAA0H4cTp5HMbwJbTVRfuebQk1/e52+21sRtr1n5yQNPSpNRSXV2rq/UoWl1WHXn9AnXfedM0hDjkptzXABAABaXVvN83Dk4uXc+/2mFn9TqJnvbdCGovJG1ycnODTsqDQd1ytdx/XqpBE9OinRZbcgUgAAgNZBMfwItfVEuWBvhd5ft1sfrNutlQX75PU1PsUd3Q7lpCdp855yeWr9kqQLhmfrzrMGKCc9qbVDBgAAaBVtPc9D5OLt3JumqYK9Ffpqe4lWby/WV9tL9PWOEtXU5fZBDpuhY7qn6rhenXRi3wyd0KczxXEAABBXKIYfoXhKlMtravXRxr0q2Fuh7LQE9ezcQT3Sk9QpySnDMLSjuEpPvLNe//hyhyTJZbfpqpN66ZLjctTR7VCCw64El00uu41RKgAAoM2LpzwPh6c9nHuvz68NRWX64vsD+mzLAX22Zb92lYR/KtTlsGl073SdNqCrTv1JF/Xt0oE8HwAAtGkUw49Qe0iUD/b1jhI9+ta3+njzviavtxlSotOuAVnJOrl/F/20f4aG5aTJaWcNVgAA0Ha0xzwPAe3x3JumqR3FVfpsy359WrBfH27Yqx3FVWH7HNUpUcdkp6pXRgf16pxU97WDMlPcMgxDtT6/PD6/arx+1dT65bAbyujotugRAQAANEYx/Ai1x0RZCiTLy9bv0ZPvbdB3eypU5fXJ5z/0r0ey26ET+nbWyf0ylJOeqLQklzoludQpyamUBGeLLNzjqfUrf1ux8rcdUJdkN4sEAQCAw9Je8zxw7qVAvr95T7mWrd+j5Rv2aOV3++Xx+Zvc12k35DfV5OuBrJQEHdszTSNyOmlEjzQd0z1VCU5GrwAAAGtQDD9CJMr1vD6/qrw+VXt8Kq2u1arv9+vDjXv13017VVzpPeTtbIaUkuhUgsMut9MW+up22JTgtCvRaVeSy65El0NJrsD3yQkOpXdwq3MHl9LrLp06uPTdnnL9d9M+fbx5rz7fckBVXl/YfSUnODSke6qGHpWmY7qnqKPbIafdJrvNkNNuyG6zKcFpU2ZygtLqxsM0FJy3uLJgvz75bp8+K9ivWr+p/pkd1b9rsn6SmayfZHZU/8xkpSY6W+R5bg7TNLWzpFprtpdofWGZuqUm6IQ+nZWTnshHWwEAaCbyvPaLc99YpadWn285oM17yrVlb4W27KvUln0V2n6gqskiuMNmyGeaOvgVpNNuqHdGB6UluZSW6FRqolNpSYGvHd0OJbrsSnDaQ68DEpx2ldd4tbfMoz3lNdpbXqO95R4VV3rUNTlBfboEutN7Z3RQr4wkJbkcrfSMAACAtqjNFcNnzZql3//+9yosLNSwYcP0zDPP6Pjjjz/k/q+++qqmTJmiLVu2qH///po+fbrOOeec0PWmaer+++/X888/r+LiYp100kl67rnn1L9//2bFQ6L843x+U9/sLNF/Nu7VZ1v2a295jQ5UeFVS5VV5TW2L3nfnDi6N6tVJe8s9+mZniaq9TXezNCXRaVe31AR1S0tQt9REVXt9WlmwX3vKapp1+67JbvXp0kF9u3RU3y4dQ4l6da1P+8o9oUR+b3mNyqtrld7BpazUBGWlJCgzJUGZKW6ld3DJMAyZdS8kTAV+Z2tq/SqrrlVptVelVd66r7XatLtca3aUaM2OEu2v8DSKqVtqgkb3TtcJfTprVK90uR021dT65an1q6bWJ0+tX35T6tzRpa7JbqUmNn5DIKjK49OBSo8MQ0rv4JLb0XSHj6fWrx3FVfp+X4V2Flerc0eX+nXtqJ7pSXI0Y3SO329qb0WNdhyo0s7iau0srpLfNDWwW4oGZ6dE/aO3pmk2+w0Dv9+UKcnOpw0AIC6R57VfnPvm8/r82l1WI4fNkNthk8sRWEPIYbep0lOrr7aX6Mutxfpy6wF9sbVYe8ubl0tHKpjDJic41DEh8DW5rsje8NVs8KWty2ELFOaTnOpU9zUt0SW7zVC11xe41PpV7fUFRr/UPc4Epz301Wm3qabWpyqPL9Ac5A189fpMpSY6Q5+IDd4P4yMBALBOmyqGL1y4UBMmTNDs2bM1evRozZw5U6+++qrWr1+vrl27Ntr/448/1k9/+lNNmzZN//u//6uXX35Z06dP1xdffKFjjjlGkjR9+nRNmzZN8+bNU+/evTVlyhStWbNGa9euVUJCwo/GRKJ8ZDy1fhVXeVRa5VW1N1CQrfH6VV33tcrrU6UnkFhWenyq9NaqyuNTaZVX+yo82l932VfhkafWr+QEh07o01kn9u2sE/tm6CeZHUOFzVqfXxuKyvXV9mKt3l6s9YVlqqn1q9ZnqtbvV63fVK3PVKWnVgd+oJPdZbdpeI80nVBXVE502bWxqFwbisq0YXe5NhaVNVp8yAp2m6GfZCbr6Kxkbd1fqdXbi+X1Hd4/YZfdpi7JbnVJdivJZdeBSq+KKz06UOlp9MZCSoJDGR3dyugYKOKXVnu1dX9lXfG68bGddkM9O3dQvy4d1bNzkjw+v8qra1VWXavymlqV1dSquNKjXcXVh/xIriRlprg1ODtVg7NT1DUlQbU+v3x+U7V+M/DVZ8rlsIU+VdDBHfiEgcthU1Fptbbuq9L3+yu0bX+ltu6v1J6yGqV3cKlLcuANiczkBHVNcSvRZdfu0hoVlVarsLRaRSXV2l1WI8OQeqQnqU/dGx59MwJf/aa0s7hKO+ouO4urVFhSLbvNUEpCoPspJdFR92It8KLIYTPksBty2AKfUrAZkscXfLPCL2/d94ahQBdVokupSU6lJQZeXLkdNvlNU34z8ALPZ5ry+wMvUoPHCb3x4TPrivl1b7TUvdkiSYYkm02y1f3bsRmG7DZDLrut7lMbgefP7bCp2uvTzuJq7Siu1I4DVdpR94aFJGUku9Wlo1sZya7A145uOe22ui6xwPnx+QP373QYctnt9S+iG7yYTnDa5LLbQ9scdkN+vxn6OLZZ95gDjzdwzMDzYMrnl+w2hd3e5bDJaTdkmoHn11vrl9dnyusL/D9g1D3m4HMQfLMj+Nw1/L8q+LsZ+hU3JVOB591X9xgDv4t++fxSgtNWf+7quuGSExyy2erf9AqeQ3/dn9zgtuCbYYYR/B0JfG345o3Pb4ZegAdfwBuGEfh0jdOuRJf9kIscB59HT4MX/DW1vtAbZm5H+Ll3O21y2OpfzJsK/4duyJDNkAzDkCHJMCS/qcD/tz6z7v/cwL/Xmrrf8eD91Xj9qvX7legM/JvtWHfp4HbI5ai/T3/oXAfu32YYshuGjLr7PRzBxx/4/W/6tqZpylv3N8Nb929IdY/NkCEZwe8lh80mm02y1/0OBd/YDP5OBB9/rd+U3TDqf78POqcHx+fzm7IZgd/NSB4nDg95XvvFuW8Zpmlq+4Eqfb+vUiVVXhVXeVRcGWiSKa70qKKmvpBc5Q28Bqip9auD2x7KMwMXl1ISnSoqqVbB3goV7KvQd3sqVFJ16Bw+liQFu98dNrkbFNXdTf1c93fPb9b/3Qt23NuMwKdbA/lj4G+I3W7IF/w72+BvbqCZJtBIE2yqKauuld0w1L1TonLSk9QjPUk5dd8nOO2hvLy8bt9yT60cNiPUsZ/kcijRFfhkrymFcrBaXyBGmQr9fXOHvtplt0me2kDuFcxvPT6/bIahjgn1f/eDF5fDFvq7F8zNbM38GxjMjTx1M+yd9kB+2fBvvWkGnqP6/CeQ37kbxH2o/CnW+P0m+QEA/Ig2VQwfPXq0jjvuOD377LOSJL/fr5ycHN1888265557Gu1/ySWXqKKiQm+88UZo2wknnKDhw4dr9uzZMk1T2dnZuuOOO3TnnXdKkkpKSpSZmam5c+fq0ksv/dGYSJRjg2maqvT4lOC0R6VLt9rr066Sau0qrtLOkmoVlgSKe6N6pWt4TtqPzjksrfbquz0V2ry7XN/tLdfm3RXavKdcW/dXqoPboc4dXMro6FbnjoGvHd0O7avwBAqtJdUqKq3WviY6uxsKFFUdSkkMzF1PTnDoqE6JGtI9Vcd0T9XR3VLC4qzy+PTF1gNa+d0+ffLdfn21o1iS5HbYGySngWR7X4XnB0fbBDnqnuvaH5gXLwUKgD3TOyg7LUF7ymu0eXdFoxE2P8RmSJkpCcpOS1R2WqL8pqlvd5aqYF9Fo4/eAm2RYSji32WbITnstlChtjn7JzrtgYXO/P6wwn1bYK974+DHwg29YK57YyPwNfAC2m4YoRfrwWLBwc9dsOBsq6tuB9+8iZSt7s2AH2MYgTciXfbAm1uhN/YOceOD47QZB70RYaiuaFC/zW4YgTdtzPoiu99sWNw3QrEYdT833K/+TZv6mMK6LZsKtO4Ni4afcmq4n63BmyYN30CR6t5oaPD83HpGf/2/U/v++JMZBeR57Rfnvm06UOHR9gNVKqv2qqymrsmiOvBp1EqPr/7NS9X/H1dd69eBCo8OVHpVUuUJNX+YpgIF6YPGOPr9CjXuVDd4c9ztsCkx+OZz3RvQdptRV+j3an+FR6XVXnLXKAo2azRsonDaDdXU+sPeTDnUbZ32+oaH5vyNdgfvo66xIlhYd9gN1frrivu1ZqjZotZvymE3Qrerb8qwhX4Pgn8Tpbo3Nxw2OW2BYzsdNrnshiQj9Hc3+KaIz2+qutanyhqfKjy1qqipVYXHF2qcCd5fw5gddce12ww56hpx7EZgnFEwDwjlBMH4DvqFNQxDdptkt9lkr8sxAg0atro3Zuqfm0DOFnit6K/Lt3z+YHOHJBkNco3gseoahOqahOw2Q4YOylv8gRjDcxwj9H3wmDZb3b/2ujQi+CaR1xd4k8jr94dyn+BjC+1uBHJHhz382EHBPCb49NQ/D/Vfg2+4BONu2OASynnqcjbV5T6hHKlB3hQ8fv3jrI/VrGv+8ZtmWH4cfA6CP9Tni4Hb1n8fiCGUcxn1WZe/QRwNG3Xqzlzofho8xY3+j61/vhp83yADPPj/w9BzaLcFnv9AYhv4nW/QTOXzm3WPQ6GmE1vdOQtrUmnwmMJz2MbnIiwXbZB7Hhyv2eD7hkK/d0b4fTel4fN1qOeq4fENoz5Gqf5rw/8/mvu3peG5rr/PH75xw9+LQ73P1jDHb+q2DZ/j+tiD3we+Gdo9TT06JzXvgRyhw8nzLB2+5vF4tGrVKk2ePDm0zWazKTc3VytWrGjyNitWrFBeXl7YtrFjx2rRokWSpIKCAhUWFio3Nzd0fWpqqkaPHq0VK1Y0WQyvqalRTU39R/tKS0uP5GEhSgzDUAd39H5FE5x29c4IzB6MREqCU8Nz0jQ8Jy3iGDy1fpVUecOKEcH/RJz2QKfz4bzjn+iy66R+GTqpX0az9q+p9WlPWY32lNVod1mNqjy+0MdHOyW51KlDYK6jaQaK/8GxL8ERMB3cDvXsnKSe6UnqkuwOi9XvN7WzpEqb91Ro0+5ybT9QqUSnXR3rPsYa+OpUSqJT3VITlJWa0OTHSctrarVuV6m+2VmqtTtLVVbjDSVQDZMQb61flZ5AohhMGKu8PnVNdqtnegf16BzohOmRnqSuKW4dqPBqd1l1qBO8qKxalR6fuiYnKCvFHRhjUzfSxucPzJH/bk954OveQGeS3Waoe1qiuncKFPC7143b8ZlmYLRNVaALqrS6VmXVXnl94V3Etb5AUhpMmBsm0KapUAdVcZVXJZVeHaj0yOszm+yYCd22QVIcTFAb/goFf8caJmGhxNsv1fj8qqnrrAl2zTjtRt3jq3+sR6UlyjCkPWWB34nA18Al2AUb7LoOJmJenxk4bqiDvb4juWFXe1MFwYbFwKaKnj7T/MHbS2rQlR/4PQvvLg/cxt3EugZOu61RwS7UGRx8sWGrT6CrvL7QuS+u9IbeFDqSF8bBbu6DJTgDXWV+v6nqBl3sflOq8Pz4m1HBj4G7nXY5bIa8Pn/onPzYG2CHw2Yo1CkW7Dh3OwL3WeX1qaKumBF8MdvcgrRZ92kBn0yp+e+9hdQn/dF5rM19ykxTYV1pzTluNOO0ii/sH8EPP5Zo/v4BQeT48aFT3TpCscrnN1VS5VVZdf2nYg/+WuMN/A0IdilX1+UKwWKbUVfwsdXlOLU+fyiP9Pr98vlM2e2GnLbwdZFcDpuSExxKSXCGGmqSExzy+kxtO1CpbfuDlypt3V8pn9+s79Kuy9GTXA75zfpPoVV6GnwSTYE8LPDJKEP2ujzU6/PXPSZfWB4RynHrCr4uh021PrOusOtTWXWgwPtDDTQ+v6kqv++wmmwa3vZQOYWr7nXHwZ9ODf19PpxJP16p7LCjOzINc4nWvm8AiNT0XwxRj849rA6jEUuL4Xv37pXP51NmZmbY9szMTK1bt67J2xQWFja5f2FhYej64LZD7XOwadOm6cEHH4zoMQCHw+UIjCixitth11GdknRUpx9+Z84wVDf/0KV+jacVNclmM0LHPvUnXSKOsaPboVG90jWqV3rEx2hKt9REDVLzu8By0pP00yN4HGg+X11XSaTjMPz+QLeOx+cPdXs4bbZDjsVoaZ5af6hLrGFR37A1fhMs2LURKvI2HPFUN94l+LFlt6PxY6r11XdJBV80Bt84sTd488DtrJ/1eig+vxl6oyLsDZW6r6F3+ht0XfhNM/ScO2y2Rl0zP8br86uyJhB7fVdLfTdI8I7DOqcadJAEvw+Ozwl21Dd8I8RhM0KxHtw9Ut+lVNf5VPcYpMbdQcHbBzuhGnawBLumHA3eKAm+oRF4QyjwhpPXF3i+7HYjNGrFUfemSsMOnWCcvro1DIIdTmFdLwc9H35/fXdG8A2kYBd5UOCx1HdyH9xJFOxIOdQ/v4b/Lg/uFgp1K9X9bAbaxkPjboLPe30cCvveygWqEb/I8dEa7DZD6R1cSo+xgn2/rh2tDuGQgiPF6v+OB7thzVAzhccXXmh3141IDC7CmuRyyNmwe9sXeBPB4/PLNBV6Iz7YRR3q6K3LG0Oj3Lz+0O2DI16C3ztsRl0nd333d7CZoOHYQ0/d6MODOy0NNXxzwy+Pz5S3tr6ZoWGeGHxTJDhOruEoyESnPawR5OCmEl/dcxB8/vymGfrbHtZZfYhO0GBnem2D/CrYzOOtDbwhU9tg/KD94FyzrmEneCzzoL/9wTGXoWP6zFAeEuwqbZg7BjuGQx3zB3VVN+yWDub9wXE5wTwsKHi7YGy+YB5n1n8NCstnFBwFWNfU1OBTfcFO4VBXbIPcJxhfMPcMvB5o2C3f4HGa9Tls8Pe/Ppczwn4/Ao+lPjc9+JN5wc56v9lwv/Bc1pRCb2gd3DXdcB+F3aa+bTp4zKbywYN/CP6mBUZNhn8qMjgaKvz3p/68hRqY/PUjM+vjavgcNPw3VP86ouG58B+U+x7qFYoRTGJV/2/j4Lw5eD4PpWGMoW1m+L+1gxvVgvsEfxfCGrEOas469P2G59cN7/PgY4SPUz1093nD5yos16/7XQnGXPcUhT7VEYq1wb8jK+tfP4RluSVNnjw5rNu8tLRUOTk5FkYEAO1HIAn64TFFP8RmM5Rgs//oqKPW4nLYor4I7KE47DYl221KTjjyQqLdZgQ+Cq7Wex6ddptSk2xKVSwWQo/szRS7Efj0TqLLLsXk4wPiHzk+EJscdpscUUo3HHYdVg4Ynjfy9xkA2iNLi+EZGRmy2+0qKioK215UVKSsrKwmb5OVlfWD+we/FhUVqVu3bmH7DB8+vMljut1uud2x+W4FAAAAgMNHjg8AAICDHfrz0q3A5XJp5MiRWrp0aWib3+/X0qVLNWbMmCZvM2bMmLD9JWnJkiWh/Xv37q2srKywfUpLS7Vy5cpDHhMAAAAAAAAAEN8sH5OSl5eniRMnatSoUTr++OM1c+ZMVVRUaNKkSZKkCRMmqHv37po2bZok6dZbb9Wpp56qJ554Queee64WLFigzz//XH/+858lBWbw3HbbbXrkkUfUv39/9e7dW1OmTFF2drYuvPBCqx4mAAAAAAAAAMBClhfDL7nkEu3Zs0dTp05VYWGhhg8frsWLF4cWwNy6datstvoG9hNPPFEvv/yyfvvb3+ree+9V//79tWjRIh1zzDGhfe6++25VVFTouuuuU3FxsU4++WQtXrxYCQkJrf74AAAAAAAAAADWM0zzh9ZDbZ9KS0uVmpqqkpISpaSkWB0OAAAAooQ8r/3i3AMAAMSnw8nzLJ0ZDgAAAAAAAABAa6AYDgAAAAAAAACIexTDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLjnsDqAWGSapiSptLTU4kgAAAAQTcH8Lpjvof0gxwcAAIhPh5PjUwxvQllZmSQpJyfH4kgAAADQEsrKypSammp1GGhF5PgAAADxrTk5vmHSFtOI3+/Xzp07lZycLMMwWuU+S0tLlZOTo23btiklJaVV7hMth/MZfzin8YXzGX84p/GlJc+naZoqKytTdna2bDYmBrYn5Pg4UpzP+MM5jS+cz/jDOY0vsZLj0xneBJvNpqOOOsqS+05JSeEfeBzhfMYfzml84XzGH85pfGmp80lHePtEjo9o4XzGH85pfOF8xh/OaXyxOsenHQYAAAAAAAAAEPcohgMAAAAAAAAA4h7F8Bjhdrt1//33y+12Wx0KooDzGX84p/GF8xl/OKfxhfOJeMHvcnzhfMYfzml84XzGH85pfImV88kCmgAAAAAAAACAuEdnOAAAAAAAAAAg7lEMBwAAAAAAAADEPYrhAAAAAAAAAIC4RzEcAAAAAAAAABD3KIbHgFmzZqlXr15KSEjQ6NGj9emnn1odEppp2rRpOu6445ScnKyuXbvqwgsv1Pr168P2qa6u1o033qjOnTurY8eO+sUvfqGioiKLIsbheOyxx2QYhm677bbQNs5n27Njxw5dccUV6ty5sxITEzVkyBB9/vnnoetN09TUqVPVrVs3JSYmKjc3Vxs3brQwYhyKz+fTlClT1Lt3byUmJqpv3756+OGH1XAtcM5nbPvwww913nnnKTs7W4ZhaNGiRWHXN+f87d+/X+PHj1dKSorS0tL0q1/9SuXl5a34KIDmIcdvu8jx4xs5fttHfh9fyPHbvraW41MMt9jChQuVl5en+++/X1988YWGDRumsWPHavfu3VaHhmZYvny5brzxRn3yySdasmSJvF6vzjrrLFVUVIT2uf322/Xvf/9br776qpYvX66dO3fq5z//uYVRozk+++wz/elPf9LQoUPDtnM+25YDBw7opJNOktPp1Ntvv621a9fqiSeeUKdOnUL7PP7443r66ac1e/ZsrVy5Uh06dNDYsWNVXV1tYeRoyvTp0/Xcc8/p2Wef1bfffqvp06fr8ccf1zPPPBPah/MZ2yoqKjRs2DDNmjWryeubc/7Gjx+vb775RkuWLNEbb7yhDz/8UNddd11rPQSgWcjx2zZy/PhFjt/2kd/HH3L8tq/N5fgmLHX88cebN954Y+hnn89nZmdnm9OmTbMwKkRq9+7dpiRz+fLlpmmaZnFxsel0Os1XX301tM+3335rSjJXrFhhVZj4EWVlZWb//v3NJUuWmKeeeqp56623mqbJ+WyLfvOb35gnn3zyIa/3+/1mVlaW+fvf/z60rbi42HS73eb8+fNbI0QchnPPPde8+uqrw7b9/Oc/N8ePH2+aJuezrZFk/vOf/wz93Jzzt3btWlOS+dlnn4X2efvtt03DMMwdO3a0WuzAjyHHjy/k+PGBHD8+kN/HH3L8+NIWcnw6wy3k8Xi0atUq5ebmhrbZbDbl5uZqxYoVFkaGSJWUlEiS0tPTJUmrVq2S1+sNO8cDBw5Ujx49OMcx7MYbb9S5554bdt4kzmdb9K9//UujRo3SRRddpK5du2rEiBF6/vnnQ9cXFBSosLAw7JympqZq9OjRnNMYdOKJJ2rp0qXasGGDJGn16tX66KOPNG7cOEmcz7auOedvxYoVSktL06hRo0L75ObmymazaeXKla0eM9AUcvz4Q44fH8jx4wP5ffwhx49vsZjjO6J+RDTb3r175fP5lJmZGbY9MzNT69atsygqRMrv9+u2227TSSedpGOOOUaSVFhYKJfLpbS0tLB9MzMzVVhYaEGU+DELFizQF198oc8++6zRdZzPtue7777Tc889p7y8PN1777367LPPdMstt8jlcmnixImh89bU/8Oc09hzzz33qLS0VAMHDpTdbpfP59Pvfvc7jR8/XpI4n21cc85fYWGhunbtGna9w+FQeno65xgxgxw/vpDjxwdy/PhBfh9/yPHjWyzm+BTDgSi58cYb9fXXX+ujjz6yOhREaNu2bbr11lu1ZMkSJSQkWB0OosDv92vUqFF69NFHJUkjRozQ119/rdmzZ2vixIkWR4fD9corr+jvf/+7Xn75ZQ0ePFj5+fm67bbblJ2dzfkEALQIcvy2jxw/vpDfxx9yfLQ2xqRYKCMjQ3a7vdEq1UVFRcrKyrIoKkTipptu0htvvKEPPvhARx11VGh7VlaWPB6PiouLw/bnHMemVatWaffu3Tr22GPlcDjkcDi0fPlyPf3003I4HMrMzOR8tjHdunXToEGDwrYdffTR2rp1qySFzhv/D7cNd911l+655x5deumlGjJkiK688krdfvvtmjZtmiTOZ1vXnPOXlZXVaAHC2tpa7d+/n3OMmEGOHz/I8eMDOX58Ib+PP+T48S0Wc3yK4RZyuVwaOXKkli5dGtrm9/u1dOlSjRkzxsLI0Fymaeqmm27SP//5T73//vvq3bt32PUjR46U0+kMO8fr16/X1q1bOccx6IwzztCaNWuUn58fuowaNUrjx48Pfc/5bFtOOukkrV+/Pmzbhg0b1LNnT0lS7969lZWVFXZOS0tLtXLlSs5pDKqsrJTNFp662O12+f1+SZzPtq4552/MmDEqLi7WqlWrQvu8//778vv9Gj16dKvHDDSFHL/tI8ePL+T48YX8Pv6Q48e3mMzxo74kJw7LggULTLfbbc6dO9dcu3ated1115lpaWlmYWGh1aGhGa6//nozNTXVXLZsmblr167QpbKyMrTPr3/9a7NHjx7m+++/b37++efmmDFjzDFjxlgYNQ5Hw5XmTZPz2dZ8+umnpsPhMH/3u9+ZGzduNP/+97+bSUlJ5t/+9rfQPo899piZlpZmvv766+ZXX31lXnDBBWbv3r3NqqoqCyNHUyZOnGh2797dfOONN8yCggLzH//4h5mRkWHefffdoX04n7GtrKzM/PLLL80vv/zSlGTOmDHD/PLLL83vv//eNM3mnb+zzz7bHDFihLly5Urzo48+Mvv3729edtllVj0koEnk+G0bOX78I8dvu8jv4w85ftvX1nJ8iuEx4JlnnjF79Ohhulwu8/jjjzc/+eQTq0NCM0lq8vKXv/wltE9VVZV5ww03mJ06dTKTkpLMn/3sZ+auXbusCxqH5eBEmfPZ9vz73/82jznmGNPtdpsDBw40//znP4dd7/f7zSlTppiZmZmm2+02zzjjDHP9+vUWRYsfUlpaat56661mjx49zISEBLNPnz7mfffdZ9bU1IT24XzGtg8++KDJv5sTJ040TbN552/fvn3mZZddZnbs2NFMSUkxJ02aZJaVlVnwaIAfRo7fdpHjxz9y/LaN/D6+kOO3fW0txzdM0zSj328OAAAAAAAAAEDsYGY4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQARWbZsmQzDUHFxsdWhAAAAAIgCcnwA8Y5iOAAAAAAAAAAg7lEMBwAAAAAAAADEPYrhANBG+f1+TZs2Tb1791ZiYqKGDRum//u//5NU//HGN998U0OHDlVCQoJOOOEEff3112HHeO211zR48GC53W716tVLTzzxRNj1NTU1+s1vfqOcnBy53W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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BgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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w5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABAYTnllFP2+2u+//3v684771T//v2zUFHPCqY6tqME2wAAAJ7xdeeLxowZoxUrVmj27Nk68sgjdeSRR+ree+/VihUrNHr06J6uEQAAAECR+93vfrdfs7m9xOaRAAAA3utWx7YklZaW6qqrrurJWgAAAAD0UrZte11CxhhFAgAA4L2Mg+0//OEPGd/pOeec061iAAAAACDfOZtHxunYBgAA8EzGwfZ5552X0e0KdWdzAAAAAMhEmI5tAAAAz2UcbFsWizYAAAAAYBQJAACA97q1eWSmxo4dq3Xr1u31+gULFujss8/WkCFDZBiGXnzxxQ7X27at22+/XYMHD1ZJSYkmT56sFStWZLNkAAAAANinoJ/NIwEAALyW1WB79erVisfje72+ublZ48aN00MPPdTp9T/72c80Z84cPfzww1q0aJH69OmjKVOmqK2tLVslAwAAAPDA5ZdfroqKCq/LyIjTsR2lYxsAAMAzGY8iyYYzzzxTZ555ZqfX2batBx98UP/3//5fnXvuuZKkxx9/XDU1NXrxxRd16aWX5rJUAAAAAN1UV1end999V1u3bt1jxOG3vvUtSdLcuXO9KK1bnM0jGUUCAADgHU+D7X1ZtWqVNm/erMmTJ7uXVVZWasKECVq4cOFeg+1oNKpoNOp+3tDQkPVaAQAAAHTu5Zdf1rRp09TU1KSKigoZhuFeZxiGG2zvS76t8Z2O7TijSAAAADyT1VEkX8XmzZslSTU1NR0ur6mpca/rzOzZs1VZWem+1dbWZrVOAAAAAHv3gx/8QFdeeaWamppUV1enXbt2uW87d+7M6D7ybY3P5pEAAADey9tgu7tuvvlm1dfXu2/72rwSAAAAQHZt2LBB11xzjUpLS7t9H/m2xg8H2DwSAADAa3k7imTQoEGSpC1btmjw4MHu5Vu2bNGRRx65168Lh8MKh8PZLg8AAABABqZMmaLFixdr1KhR3b6PfFvjB5mxDQAA4LmsBtuPPPLIHqNEMjVy5EgNGjRI8+bNc4PshoYGLVq0SN/73vd6sEoAAAAA2TJ16lTdeOON+vTTTzV27FgFg8EO159zzjkeVdZ9bB4JAADgvYyD7Tlz5mR8p9dcc40k6Z//+Z/3ebumpiZ98cUX7uerVq3Shx9+qOrqag0fPlzXXXed7r77bh188MEaOXKkbrvtNg0ZMkTnnXdexrUAAAAA8M5VV10lSbrzzjv3uM4wDJmmmeuSvjJnxnaUYBsAAMAzGQfbDzzwQEa3MwzDDba7snjxYn396193P581a5Ykafr06Xrsscd00003qbm5WTNmzFBdXZ1OPPFEvfrqq4pEIpmWDQAAAMBDllV84a8TbMeZsQ0AAOCZjIPtVatW9fg3P/XUU2Xb9l6vNwxDd955Z6fdHQAAAADghRCbRwIAAHgubzePBAAAAFCY5syZoxkzZigSiXQ50jDTV3vmE2ZsAwAAeK/bwfb69ev1hz/8QWvXrlUsFutw3f333/+VCwMAAABQmB544AFNmzZNkUhknyMN92eMYT5xO7YJtgEAADzTrWB73rx5OuecczRq1Ch9/vnnGjNmjFavXi3btnX00Uf3dI0AAAAACkj6GMNsjDT0Gh3bAAAA3vN154tuvvlm3XDDDVq6dKkikYief/55rVu3Tqeccoouuuiinq4RAAAAAPIGM7YBAAC8162O7c8++0xPPvlk8g4CAbW2tqqsrEx33nmnzj33XH3ve9/r0SIBAAAAFK5iG2PoBNtx05Zt2zIMw+OKAAAAep9uBdt9+vRxF6SDBw/Wl19+qdGjR0uStm/f3nPVAQAAAChoxTjG0Am2pWTXdjjg97AaAACA3qlbo0iOP/54vfXWW5Kks846Sz/4wQ/0k5/8RFdeeaWOP/74Hi0QAAAAQOEqxjGGzoxtiTnbAAAAXulWx/b999+vpqYmSdIdd9yhpqYmPf300zr44IML8qWEAAAAALKjGMcYEmwDAAB4r1vB9j333KPLL79cUnIsycMPP9yjRQEAAAAoDsU4xtDnMxTwGUpYNhtIAgAAeKRbo0i2bdumM844Q7W1tbrxxhv10Ucf9XRdAAAAAIpAsY4xdOZs07ENAADgjW4F2y+99JI2bdqk2267Te+9956OPvpojR49Wvfcc49Wr17dwyUCAAAAKFT333+/JkyYICk5xvC0007T008/rREjRug3v/mNx9V1nxNsx+nYBgAA8ES3RpFIUt++fTVjxgzNmDFD69ev15NPPqn/+q//0u23365EItGTNQIAAAAoQKZpav369TriiCMkFdcYQ2fOdpSObQAAAE90q2M7XTwe1+LFi7Vo0SKtXr1aNTU1PVFXwdra0KZH5n+p//e/K70uBQAAAPCU3+/X6aefrl27dnldSo9jFAkAAIC3uh1sv/HGG7rqqqtUU1OjK664QhUVFXrllVe0fv36nqyv4Gxvimn2nz/Xw/MJtgEAAIAxY8Zo5criWxs7HdsE2wAAAN7o1iiSoUOHaufOnTrjjDP061//WmeffbbC4XBP11aQKkuDkqSG1rhs25ZhGB5XBAAAAHjn7rvv1g033KC77rpLxxxzjPr06dPh+oqKCo8q+2rcjm1mbAMAAHiiW8H2j3/8Y1100UWqqqrq4XIKX2VJMtiOmZba4pZKQn6PKwIAAAC8c9ZZZ0mSzjnnnA5NH04TiGmaXpX2lTCKBAAAwFvdCravuuqqnq6jaPQJ+eX3GTItW3WtMZWESrwuCQAAAPDMo48+qtraWvn9HRs+LMvS2rVrParqq3NGkcTp2AYAAPBEt4Jt7J1hGKoqCWpHc0z1rXENriTYBgAAQO915ZVXatOmTRo4cGCHy3fs2KHJkydr+vTpHlX21Tgd21E6tgEAADzR7c0jsXfOOJL6lrjHlQAAAADe2tu+M01NTYpEIh5U1DMYRQIAAOAtOrazoMIJtlsJtgEAANA7zZo1S1LyFY233XabSktL3etM09SiRYt05JFHelTdVxf0s3kkAACAlwi2s8Dp2K4j2AYAAEAv9cEHH0hKdmwvXbpUoVDIvS4UCmncuHG64YYbvCrvK6NjGwAAwFsE21lQVZoMthsItgEAANBLvfHGG5Kkb3/72/rFL36hiooKjyvqWWE/wTYAAICXCLazoJJRJAAAAIAk6dFHH/W6hKxwOrbjjCIBAADwBJtHZgHBNgAAAFDcGEUCAADgLYLtLHBnbLcQbAMAAADFyNk8MkrHNgAAgCcItrOAjm0AAACguNGxDQAA4C2C7Swg2AYAAACKW4jNIwEAADxFsJ0FTrDdQLANAAAAFCU6tgEAALxFsJ0FlaWpGdsE2wAAAEBRCqeC7TgztgEAADxBsJ0FVSUhSclRJLZte1wNAAAAgJ7mdmwTbAMAAHiCYDsLnFEkpmWrOWZ6XA0AAACAnhZkxjYAAICnCLazIBL0uZvJsIEkAAAAUHyc9X6UYBsAAMATBNtZYBiGKlJd23UtMY+rAQAAANDT2DwSAADAWwTbWVKV2kCSjm0AAACg+DBjGwAAwFsE21nizNluINgGAAAAio4TbMcJtgEAADxBsJ0lTrBNxzYAAABQfMJsHgkAAOApgu0sqXRnbBNsAwAAAMUmyIxtAAAATxFsZwkd2wAAAEDxCtGxDQAA4CmC7Swh2AYAAACKF5tHAgAAeItgO0sItgEAAIDi5QTbUTq2AQAAPEGwnSUE2wAAAEDxckaRxOnYBgAA8ATBdpZUlRJsAwAAAMUqzOaRAAAAniLYzhI6tgEAAIDiFUx1bFu2lKBrGwAAIOcItrOEYBsAAAAoXs6MbYkNJAEAALxAsJ0l6cG2ZdkeVwMAAACgJ3UIthlHAgAAkHME21lSkQq2bVtqjCY8rgYAAABATwr4DBlG8mOCbQAAgNwj2M6SSNCvSDD59DYwjgQAAAAoKoZhKJSas80oEgAAgNwj2M4i5mwDAAAAxcsZR0LHNgAAQO4RbGeRE2zXtRBsAwAAAMWGjm0AAADvEGxnUVVJSBId2wAAAEAxomMbAADAOwTbWVTBKBIAAACgaBFsAwAAeIdgO4uYsQ0AAAAUL3cUCcE2AABAzhFsZ5E7Y7s15nElAAAAAHqa27HNjG0AAICcI9jOoqrSZLDdQMc2AAAAUHQYRQIAAOAdgu0sYhQJAAAAULyCfjq2AQAAvEKwnUUE2wAAAEDxCtOxDQAA4Jm8D7Z//OMfyzCMDm+HHnqo12VlxJ2x3UKwDQAAABQbNo8EAADwTsDrAjIxevRovf766+7ngUBBlK3KUjq2AQAAgGLF5pEAAADeKYiEOBAIaNCgQV6Xsd8YRQIAAAAULzaPBAAA8E7ejyKRpBUrVmjIkCEaNWqUpk2bprVr13pdUkacYLuxLSHTsj2uBgAAAEBPCrF5JAAAgGfyvmN7woQJeuyxx3TIIYdo06ZNuuOOO3TSSSfp448/Vnl5+R63j0ajikaj7ucNDQ25LLcDJ9iWpIbWuPr2CXlWCwAAAFCo8mmNny5IxzYAAIBn8r5j+8wzz9RFF12kI444QlOmTNGf/vQn1dXV6Zlnnun09rNnz1ZlZaX7Vltbm+OK2wX9PvUJ+SUxjgQAAADornxa46dj80gAAADv5H2wvbuqqip97Wtf0xdffNHp9TfffLPq6+vdt3Xr1uW4wo6Ysw0AAAB8Nfm2xneE6dgGAADwTN6PItldU1OTvvzyS33zm9/s9PpwOKxwOJzjqvauoiSojfVtBNsAAABAN+XbGt/hbh7JjG0AAICcy/uO7RtuuEHz58/X6tWr9fe//13nn3++/H6/LrvsMq9Ly4jTsV1HsA0AAAAUFWcUSZxgGwAAIOfyvmN7/fr1uuyyy7Rjxw4NGDBAJ554ot555x0NGDDA69IyUlXKKBIAAACgGDkd29E4wTYAAECu5X2w/dRTT3ldwlfidGw3EGwDAAAARWVAeXI8yqb6No8rAQAA6H3yfhRJoWPzSAAAAKA4jejfR5K0ekezx5UAAAD0PgTbWebO2G6JeVwJAAAAgJ40sl8y2N5U36bWmOlxNQAAAL0LwXaWVZaGJNGxDQAAABSbqtKgKiLJ6Y5rdtK1DQAAkEsE21nGKBIAAACgOBmGoZHOOJLtBNsAAAC5RLCdZe2jSAi2AQAAgGLjzNletb3F40oAAAB6F4LtLHOC7QY6tgEAAICiM6IfHdsAAABeINjOsipGkQAAAABFyxlFsmoHwTYAAEAuEWxnmdOx3RwzFTctj6sBAAAA0JOcUSRrCLYBAAByimA7yypSwbZE1zYAAABQbEamRpFsaYiqJZbwuBoAAIDeg2A7y/w+Q+XhgCSCbQAAAKDYVJYG1bc02cyymg0kAQAAcoZgOwcqS5mzDQAAABSrA5wNJBlHAgAAkDME2zlQyQaSAAAAQNFyN5DcTrANAACQKwTbOeAG2y0E2wAAAECxGeF0bBNsAwAA5AzBdg7QsQ0AAAAUrxH9SyUxigQAACCXCLZzoIoZ2wAAAEDRckaRrN7B5pEAAAC5QrCdAxV0bAMAAABFa0Qq2N7WGFVTNOFxNQAAAL0DwXYOOKNI6pixDQAAABSdikhQ/fqEJDFnGwAAIFcItnOAGdsAAABAcRvhjiMh2AYAAMgFgu0cqCpJdm80EGwDAAAARemAfqkNJOnYBgAAyAmC7RygYxsAAAAobiP7JTu2V21nA0kAAIBcINjOAXfGdmvM40oAAAAAZAOjSAAAAHKLYDsH6NgGAAAAittIJ9hmFAkAAEBOEGznQGVpMthui1uKJkyPqwEAAADQ05yO7R3NMTW00dACAACQbQTbOVAeDsgwkh/TtQ0AAAAUn7JwQP3LwpKkNczZBgAAyDqC7Rzw+QxVRFLjSFoItgEAAIBiNLJ/qSRpFXO2AQAAso5gO0eYsw0AAAAUtxH9mLMNAACQKwTbOVJVSrANAAAAFLMRbCAJAACQMwTbOULHNgAAAFDcnI5tRpEAAABkH8F2jlSkgu06ZmwDAAAARWlEasY2HdsAAADZR7CdI3RsAwAAAMXN6dje1RJn03gAAIAsI9jOkSqCbQAAAKCo9QkHNLA8LElazTgSAACArCLYzhGnY7uBYBsAAAAoWu4GkgTbAAAAWUWwnSNOsL2tKepxJQAAAACyZaSzgSRztgEAALKKYDtHxgytlCQt/HKHNtW3elwNAAAAgGxwO7YJtgEAALKKYDtHxgyt1PGjqpWwbP3XW6u8LgcAAABAFozoVypJWrWjxeNKAAAAihvBdg796ykHSpKeWLSWTSQBAACAIkTHNgAAQG4QbOfQqV8boENqytUcM/X7RWu8LgcAAABADxuRmrFd3xrXruaYx9UAAAAUL4LtHDIMQ/96yihJ0qNvr1Zb3PS4IgAAAAA9qSTk16CKiCRp9Q66tgEAALKFYDvHzh43REMqI9rWGNWLH2zwuhwAAAAAPWxE/9ScbcaRAAAAZA3Bdo4F/T5deeJISdKvF6yUZdkeVwQAAACgJx0+uFKS9F9vr1LCtDyuBgAAoDgRbHvg0uOGqyIS0MrtzXrtsy1elwMAAACgB333lFGqLAnq4w0N+vX/rvS6HAAAgKJEsO2BsnBA35x4gCTp4flfyrbp2gYAAACKxcCKiG7//w6XJD34+gp9sbXJ44oAAACKD8G2R6afMEKhgE8frK3T4jW7vC4HAAAAQA+64OihOvWQAYolLN303EcyGUEIAADQowi2PTKwPKILjx4mSXpk/pceVwMAAACgJxmGoXvOH6uycEDvr63Tf/99tdclAQAAFBWCbQ9dddJIGYb0+mdbtXxLo9flAAAAAOhBQ6pKdMtZh0mSfvaXz7VmR7PHFQEAABQPgm0PjRpQpimHD5IkXfFf7+qjdXXeFgQAAACgR112XK0mjuqntrilHz6/VBYjSQAAAHoEwbbHbp16mEYN6KON9W266OGFevLdtV6XBAAAAKCHGIahey8cq5KgXwtX7tCT77HeBwAA6AkE2x6rrS7VSzMn6RuH1yhmWrr5f5bqh8//Q21x0+vSAAAAAPSAA/r10Y1TDpEk3fPHz/TMe+sUNy2PqwIAAChsBNt5oDwS1COXH6Mbpxwiw5Ceem+dLnlkoTbWtXpdGgAAAIAeMP2EEZowslrNMVM3Pf8PTb5/vp5bsl4JAm4AAIBuMWzbLuohbw0NDaqsrFR9fb0qKiq8LqdL85dv07VPfaC6lrgqS4I6/fAaHT+qn44/sJ+GVpV0+jWmZWtrY5sqIkH1CQdyXDEAAIA3Cm2dh55TqMe+LW7qd++s0dw3v9SO5pgkaWT/PrrmtIN0zrih8vsMjysEAADw1v6s8wi289C6nS36198u0aebGjpcPry6VMePqtbw6lJtqGvV+l2tWrezRRvqWhU3bfUJ+XXFpBG66qRRqioNeVQ9AABAbhTiOg89o9CPfUssod8uXKNHFqzUzlTAXVMR1lG1fTV2WKXGDavS2KGVqiwNelwpAABAbhFspynURW8sYentL7dr0cqdemflDi3dUC9zHzuoG4bkHMnycEBXnjhSV544UpUlLIYBAEBxKtR1Hr66Yjn2zdGE/nvhav16wUrVtcT3uH5Ev1IdNbyvxo/oq2NHVOugAWXy0dUNAACKGMF2mmJZ9DZFE1q8eqfeWblT25uiGlpVomF9S1RbXara6lLVlIc17/OteuC15fp8c6MkqSIS0FUnjdKUMYNUHgmoPBJUn5BfhsFiGAAAFL5iWedh/xXbsW+NmfpofZ2Wrq/XR+vr9I/19Vq7s2WP21WWBDX+gL4aP6JaJxzYT2OHVhJ0AwCAokKwnabYFr1dsSxbf/54sx58fblWbG3a43qfIZWFA6osDerwwRWaMLKfJoyq1mGDKjxZFG9viuqDtXUaUhXR12rKFfT3vv1MW2IJlQQ54QAAwP7qbes8tOsNx35Xc0z/2FCvJWt2afHqnfpgbZ1a42aH21T3Cenkg/vrlEMG6KSDB6h/WdijagEAAHoGwXaa3rDo7Yxp2XrlHxv1//53ldbtalFjW2Kfo0wqIgEdN7Kfxo/oq359QioLB1QWCahPOKCycEClIb9Cfp+Cfp+CAZ+CfkNBn88Nw23blm1Llm3LlhTwGXsNaldtb9Zrn27WXz/ZoiVrd7kjVEJ+nw4dXK4xQys1dmilvlZTJkmKm7bipqW4aSmWsBX0GzqgX7JTPRzwd7hv27a1anuzFq7coYVf7tDi1bskScP6tne4Jz8u1YEDylRTEc55oFzfGtc7K3fo719s11tfbNeX25o1uDKikw8eoJO/NkAnHtSfeYoAAGSgt67z0DuPfdy09OnGBr23eqcWrdqphV/uUFM00eE2Y4ZW6LBBFRrRv48O6FeqEf36aET/PipL22DetGxFE6aicUvhoE+lITafBwAA+YNgO01vXPR2xrZttcZNNbYl1NgW1/ammN5fu0uLVu7U4tU71Rwzu76TTqTP9k4X9BvqWxpSdZ+Q+pWFVN0nrLJwQO+t3qkvduskP2hgmbY2tKmhLbHnHe2Dz5CG9i3RiH59NLJ/Hzcw3tIQzfg+KkuCOmRQuQ4dVK6v1ZRrVP8+ao6Z2tEU1Y7mmLY3RbWjKaaWWELVfULqXxbWgPKw+76yJCi/z5DPkHyGIZ9hyO8z1Bo3tas5pl0tcdW1xLSzJaYdTTEtXrNLS9fXaR/nGOQzpCNrqzRhVD8FfYaiCSv1lvwPiCT1Lw9rYHmyhgFlYQ2sCCsc8KuhLZ46xgk1tMbVFE3I5zNUWRJUZUlQFZGAKkuCKo8EVd8a15aGNm2qb0u9b9XO5phqKiIa2b+P+zakssQ9gZEwLdW1xrWrOaYdzTFta4xqY12rNta1akNdmzakPg4FfBo9pEJjhlRqzNAKjR5SqWF9S7p1EqGxLZ7cLHVnq9bvalFDW0KDKyMa1jd5kmJwZUSBVKe/bdva3hTT+l3JTVU37GpVOODTwTXlOrimTAPKOj+R0RJLaN3OVm2sb1XI71N5JOCe3CkPBxUJ+jKqPWFaamxLyDCSP1v50oXvPC+rdzRr1fZmrd3RoqDfp8FVEQ2pLHHfl4T8Xd8Z8o5t20pYdk5e8dIWN9UUTf6NaYubKgsHVBEJqiwSkL8AXgpv27ZMy07+vS6AetE11nm9F8c+uSfP+2t3af7ybZq/bNseG8+nK48EUoG21aHZxTCkgweW6ajavjpqeJWOHF6lgweWF8TfdAAAUJwIttOw6O1awrT0ycYGLVq1Q0s3NKihNa7maEJNqbfmaELNMVNx0+o0xN5fAZ+hiQf20zcOr9Hkw2o0pKpEtm1r7c4WLd1Qr6Ub6vXJhgat2t6sgN9Idon7fQqlPm6JmVqzo3mvYXzI79NRw6s08cB+mjCyn0pCfq3f1aL1u1rd92t3tmjNjpZ9drFn06gBfTTpwP6adFB/HT28Sp9tbtSC5ds0f/m2PYJ/r4UCPg0sD6uxLaH61j03NcpUZUlQfUuDSljJYMl5b1q2Ar7UcQ4YqWOdDOg21bd1+T19hjS4skThgE8b6loVTVh7vW1VaVBfG1iuAweWqS1uau3OFq3d2aJtjfs+GeL3GSoJ+lUS8qs05Hc/9htG8iRCWzz5e5P2Mxn0GxqQOgHivPl9hlqiplpiplriplpjCbXGTdm2UidIkidG/IYhw5CiCUttcTP1Zqk1nvw99PsMhfw+BfyGAr7UKyicV1SkPnZ+d+pa4lq9vVmN0a5PHFWWBFPhqC3LTr0SQ8mTVwFfsrag3ye/z1DAn6whEmx/PkpSz43PkFrjlvv4WmKmWmOmEpYt55+c9N+8cCD5vDpvfUIBhYN+xRKWWuOJ5POVuo9owkw+5kDyb4LzsSS1xtpv2xxNuN/TqTX974lt24qbtmKmpYRpKW7aSliWIkF/8qRGOODuTVAa8stWctSTadmybOd9MhBIntSSDMOQoeRlppV8/iw7eTvLthVLWGpLWIqmHdNowlQo4FN5JOh+v/LU97dlK2Hailu2W2PMtJJ/n9sSqYA5eQLLSh2jktTzV5o6HpGg3/39Sv95sW0plnolTDRhua+KSZjtr74xU6/ESViWmqOmmtoSipl7//0qDwdUUZJ8vgJ+X9rPTPK9ISP5O2+3P48J025/Dn2G/Gkfm2mPO25aSljJYyRJhpK/I8nnO3XizbJkmnbqdsmvTf9+zjFzBHyGQgFf8s2ffG8YkmWpwzF2fmaN1O+lz2j//o70fxvTj7lp2bJSj1WSAqnf0YCv/efRSP0+pP++Wann3rnMuU/bTn5/f+q5Tf97YdlKe5y2+/vmPA7nPp33Sv2sJp/PrjmP30j7eG/uOX+szho7OIN7/epY5/VeHPs9bW1o06JVO7Vqe7NW72jWmh0tWr29WTuaY/t1P31Cfh04sEyVJUFVlYZUWRJQVUlIVaVBlYYCKgn5FAn4FUn9ux8K+FTfGtf2xqi2NyUbQ7Y3RdXUltDgqohG9i/TyP6lGtm/TMP6lvTK0YMAACBzRRdsP/TQQ/r5z3+uzZs3a9y4cfrlL3+p4447LqOvZdHbs0yrfSyIEwT53DCnPdRpjpluV6/zvr4lpgMHlunUQwaqsuSrjdqwbVvbmqJata051YXaonDApwmjqnX08L6KBLvuPG2Lm/pyW5OWbW7Usi2NWra5UWt3tKi8JKj+qU7zfmVh9esTUmkooJ3NycX6tsaotjVFtb0xqoa2RDI4sJ3wIvkcRYI+9S1N/gcg+T6kvqXJ7vBJB/XXkKqSvda1oa5V/7t8m/6xoV4Bn6FwwKdwwJ98H/TJtJKzybc1Jt+2NrZpa2NUcdPqEI5VRJKdlAnLUn1rXPWtyS7uhta4GqMJlYcDqqmMaHBlRDUVyfd9S0Pa3NCmlduatWp7k9bubFHc3PNPRFVpUNWlyQ72IVURDakq0ZCqEg3tW6IhlSVqiSX08cYGfZI6UbF8S2On95OpvqVBt0O7PBLQpvo2bdjVqvV1rYrtFmQbhjSoIqKhqXpaYqZWbGnUmp0t+zwxUxEJaGjfUpmWpaa2hBpTJ3by/y9kZgxDGlJZopGplyYnTFsb61u1qb5Nm+pau/2qDfROZeGAwgGfmqKJfZ5MQu/0i0uP1LlHDs3J92Kd13tx7DPX0BbX1oaoQv7kWjL9/a6WuD5cV6cP1u7Sh+vq9NG6uqyuCQI+Q4OrIslX+4QD7tq1LBxQJOhz113OiT5J7rq60l1XB1WV+r9EW9xSWyJ5wjgatxQzreT6OZhcO0dS74N+w20SaI2Z7ntbthva9y0NqW9pSOWRAK/qAQDAQ0UVbD/99NP61re+pYcfflgTJkzQgw8+qGeffVbLli3TwIEDu/x6Fr3AnizLzmjBnjAtbaxr09bGNnfBX1kSdEd/ZCqaMLViS5Pa4may29fndI+2d2bGEsn/jMRT7y07FVD3LekwF3L3x7G9Kap1u1oVTZgaVlWqQZURhQJ71tcWN/XF1iat2NqoL7c2q084oOHVpe5bZ3PNLSs5wqcpmnA7hp0O4taYKdOyVVESVEUkqIqS9pEMVmr0h3PywTkBYdnJLqhkN217V60hp7tTbrelZdsKB5KdUJFg8j9mkWBy1n3CSnavxhKW25kaS3Xbpp94iiUslUUCGtm/j4ZXl+71hI9t22poS2hLQ5sSpi2fr70j1fkxMa1kR2zCbO+2j6U6ylviptqc/yTGk89Leme7897p0HJ+8gzDkG0nXxad7LROuO9bY5ZCAZ/7HDnd3OGA333McdNSzEx+7D63qT0BnM5vv89wu32d5ytuWvIZSnUvt3e5+32GoglTDW3tHdHOe8OQ+/PqT3UU+1L1O9226V2x6Z20yQ7k5PeLpB/PQLLLLW5aHcYINaW6sA3DcLt7g34j1e3rc7vJ28flBBQK+Dp0x7fETDXHEorGLfe4OT8jCcuSYRgK+VMdy35/8jkIJLusnbFKTmewYRjt3zMScJ/X9N9vZ/xRY1tCzbGEEmb7KzMSqeffsm0FfD6309h5Pp3ftfSffctOPm+7vwLB+b7JlUuqqzlVh9+X3PvBeUVBIL2rOa272e8zZNnJl/An/+6YiqY+ltrHSvl8yY+dzuSOndSSLVtG6qc5vXvZMNpfgZH+KgxbtntCOJ6wFbecDnm7025o5xj43OuczmxblqVUJ7olM9Vhnv6qD/c4+tTh59W5v46//6n3aY9nj78Rac91e8e3rb31eg+sCKsikpu9Iljn9V4c++wwLVsrtjZq/c5W1bfGVdcaV31LzP24OZp89VRrzFSb8z5uqaIkqP5lIQ0oC6t/eVj9y0LqEw5ow65Wrd7RrJWpZpS2eP6fDPUZqRO4qX+znQYTJyR3mk6c65x1p/NvWPorZZL/FnV8tY7PMGRazhqu/d/KtoSlxtSrAJ1XBDa2JRQO+FRbndxfqLZvqWqrS1Tbt1R+X/KVg8n1Sjz1altTIb/hdtM7a7BwwO8246S/akpKvjrTeYyh1OMzDEOxtFd0Oev0oN/n7sHkrEPKQgEFA4b775XfaP84k7F8pmWrLfWqRPff/LS9nCS5r7SLJkx3TKPPUIe697XHUz7J9P9hANCbFVWwPWHCBB177LH61a9+JUmyLEu1tbX6t3/7N/3whz/s8utZ9AIAABQn1nm9F8e+8FiWrc0NbdpY15p8ZVzaSeTGaELRuCl1Mu6pNWaqriWW3OcltX9NXUtcPkPuiX8neHYaAJxxX8n3yXA2ktooMzlGzefuLVLXElddS1y7WmJq4RVsPSqYGgfnjv4K+BTw+dSWaoZoiZl7vPrSEUidqJaS4/m6Si2coDuYOnGfPqYv4PMpbqWC+oSdao5IjiwL+tvHkjkhud9n7PbqgeQnzli+UNoIxYCvfa8f02l0SJ2wTz7GhJqjqfepx+uMFdx9JJpzUj7gT50Q8bWPG2sfS5a87/T6dn8eOow4TJ1gbx/Jl2qWSJ10cU7GmKmRb844veTvYPqJd7U3KLl1Jj+W2uuTbHesm7FbLb60kx7pY/yc8+SJVMOKM4YvYbaPc5PaT5Q4jQB+357370gf8eYcO+fkv1O703jgPK9uA4PaH7PPrdFwx8fJORapZ99Qqnlgt1qS99f+qm7bbh+L5zyvzv22jzZMPrYOn6f9TXSfM+02Zi71uftc7dZ80d5YtOd1SnuekkfQ7vRy5/lobx5JHn9btttokf7zZOzWKOPf7TEpvakj7fE4x8T5PP05cI6L8xg6q9XupPb059xndPzenUl/vvb2XHX23Di38xlGWh12p/V0+n07NMt0/Hne99e1T0/oTGd/z3b/2vZmmvTbOh8nP5gwsp8GlIe7fiA9YH/WeXm9BXYsFtOSJUt08803u5f5fD5NnjxZCxcu7PRrotGootH2ebkNDXvfRAUAAABA/mONX/h8PsMdX5evoglTdS3J7udoasxJtENI3t4xHI2b7ntJe7yqy2eofW+ZtLDOtOTuP+EEgwG/oXDAr/LUKMGKSHLfivJIQC2x5L4w63a27xW0fleLJKk8NdLFeQVXaSighGV1GLfSmtrbY4+wMxVIxlKPJ5barD6WsGTadips9bv7HAVTJw2aoqaaosnu/aZoYq/BtKTUPhlmt8bbOHtmdCbk97n7STgsW6lXD+7vd8r9yQzTstVqJY8NABSK3//LhJwF2/sjr4Pt7du3yzRN1dTUdLi8pqZGn3/+eadfM3v2bN1xxx25KA8AAABADrDGRy6EA37VVPhV0/VNc+qwwfn7qoRYon2zZsu2Zac6N51Nn2NuaN7eJV2S6rQvSRuZEvAbaaPT2jePlqRw2kiYkL99TIk7zjDRftIhnva1zpjDRKoz2xlx5nR0+w1DsbRRK859xS1rjz2kDBkybVvxhNV+32k1OiPo3M5kn6HSYGqcXjjgjsyLBHzuiDznhIKzobczMs4ZU2NaljueLb0T2+kOdaR3aSa7g60OIw4TaR3QzvPrnDjwp53s8LnjzOR2LjsdtE5nsDNuLp7atDueOrngjDtzOrEd7qg5Zz+q3TbITu9idsbQON3lgbQTMOmdo8la5N6vmfZe6tiR3N7drA4j8pyRebvXnT6CTmn1Od83vas1/XF2GEOUqiW9W9lnOD8jhnu/6c+vs0m4ndaFbe32PHXsoJW76brSOssNY++dy7baZ/g599lVx7LzgSHDfVVCIrU5uvN8Oh3mfl/6hvCp31F7t83MLbtD13D7c7Dnz5CzYXv685M+irCzyo3dCu94PDsbrde53butnfvYvaPa6eJ3bpfeRd/h5zDtedwXpzM6vSt8967x9G719BGJe3s86a9AcL7eqcn5eiv95yytSz71Be7X52rU4P7K62C7O26++WbNmjXL/byhoUG1tbUeVgQAAADgq2CND+Snzva26a6gXypR53vCdMbvM5LheMgvKT8DFwBAduV1sN2/f3/5/X5t2bKlw+VbtmzRoEGDOv2acDiscDj/WuMBAAAAdA9rfAAAAOyu506vZkEoFNIxxxyjefPmuZdZlqV58+Zp4sSJHlYGAAAAAAAAAPBKXndsS9KsWbM0ffp0jR8/Xscdd5wefPBBNTc369vf/rbXpQEAAAAAAAAAPJD3wfYll1yibdu26fbbb9fmzZt15JFH6tVXX91jQ0kAAAAAAAAAQO+Q98G2JF199dW6+uqrvS4DAAAAAAAAAJAH8nrGNgAAAAAAAAAAuyPYBgAAAAAAAAAUFIJtAAAAAAAAAEBBIdgGAAAAAAAAABQUgm0AAAAAAAAAQEEh2AYAAAAAAAAAFJSA1wVkm23bkqSGhgaPKwEAAEBPctZ3znoPvQdrfAAAgOK0P2v8og+2GxsbJUm1tbUeVwIAAIBsaGxsVGVlpddlIIdY4wMAABS3TNb4hl3kLS6WZWnjxo0qLy+XYRg5+Z4NDQ2qra3VunXrVFFRkZPviezheBYfjmlx4XgWH45pccnm8bRtW42NjRoyZIh8Pibs9Sas8fFVcTyLD8e0uHA8iw/HtLjkyxq/6Du2fT6fhg0b5sn3rqio4Je1iHA8iw/HtLhwPIsPx7S4ZOt40qndO7HGR0/heBYfjmlx4XgWH45pcfF6jU9rCwAAAAAAAACgoBBsAwAAAAAAAAAKCsF2FoTDYf3oRz9SOBz2uhT0AI5n8eGYFheOZ/HhmBYXjieKBT/LxYXjWXw4psWF41l8OKbFJV+OZ9FvHgkAAAAAAAAAKC50bAMAAAAAAAAACgrBNgAAAAAAAACgoBBsAwAAAAAAAAAKCsE2AAAAAAAAAKCgEGz3sIceekgjRoxQJBLRhAkT9O6773pdEjI0e/ZsHXvssSovL9fAgQN13nnnadmyZR1u09bWppkzZ6pfv34qKyvThRdeqC1btnhUMfbHvffeK8MwdN1117mXcTwLy4YNG3T55ZerX79+Kikp0dixY7V48WL3etu2dfvtt2vw4MEqKSnR5MmTtWLFCg8rxr6YpqnbbrtNI0eOVElJiQ488EDdddddSt/TmmOa3xYsWKCzzz5bQ4YMkWEYevHFFztcn8nx27lzp6ZNm6aKigpVVVXpO9/5jpqamnL4KIDMsMYvTKzvix9r/MLHGr+4sMYvbIW4vifY7kFPP/20Zs2apR/96Ed6//33NW7cOE2ZMkVbt271ujRkYP78+Zo5c6beeecdvfbaa4rH4zr99NPV3Nzs3ub666/Xyy+/rGeffVbz58/Xxo0bdcEFF3hYNTLx3nvv6ZFHHtERRxzR4XKOZ+HYtWuXJk2apGAwqD//+c/69NNPdd9996lv377ubX72s59pzpw5evjhh7Vo0SL16dNHU6ZMUVtbm4eVY29++tOfau7cufrVr36lzz77TD/96U/1s5/9TL/85S/d23BM81tzc7PGjRunhx56qNPrMzl+06ZN0yeffKLXXntNr7zyihYsWKAZM2bk6iEAGWGNX7hY3xc31viFjzV+8WGNX9gKcn1vo8ccd9xx9syZM93PTdO0hwwZYs+ePdvDqtBdW7dutSXZ8+fPt23btuvq6uxgMGg/++yz7m0+++wzW5K9cOFCr8pEFxobG+2DDz7Yfu211+xTTjnFvvbaa23b5ngWmn//93+3TzzxxL1eb1mWPWjQIPvnP/+5e1ldXZ0dDoftJ598MhclYj9NnTrVvvLKKztcdsEFF9jTpk2zbZtjWmgk2S+88IL7eSbH79NPP7Ul2e+99557mz//+c+2YRj2hg0bclY70BXW+MWD9X3xYI1fHFjjFx/W+MWjUNb3dGz3kFgspiVLlmjy5MnuZT6fT5MnT9bChQs9rAzdVV9fL0mqrq6WJC1ZskTxeLzDMT700EM1fPhwjnEemzlzpqZOndrhuEkcz0Lzhz/8QePHj9dFF12kgQMH6qijjtJ//ud/utevWrVKmzdv7nA8KysrNWHCBI5nnjrhhBM0b948LV++XJL00Ucf6a233tKZZ54piWNa6DI5fgsXLlRVVZXGjx/v3mby5Mny+XxatGhRzmsGOsMav7iwvi8erPGLA2v84sMav3jl6/o+kJV77YW2b98u0zRVU1PT4fKamhp9/vnnHlWF7rIsS9ddd50mTZqkMWPGSJI2b96sUCikqqqqDretqanR5s2bPagSXXnqqaf0/vvv67333tvjOo5nYVm5cqXmzp2rWbNm6ZZbbtF7772na665RqFQSNOnT3ePWWd/gzme+emHP/yhGhoadOihh8rv98s0Tf3kJz/RtGnTJIljWuAyOX6bN2/WwIEDO1wfCARUXV3NMUbeYI1fPFjfFw/W+MWDNX7xYY1fvPJ1fU+wDXRi5syZ+vjjj/XWW295XQq6ad26dbr22mv12muvKRKJeF0OviLLsjR+/Hjdc889kqSjjjpKH3/8sR5++GFNnz7d4+rQHc8884x+//vf64knntDo0aP14Ycf6rrrrtOQIUM4pgCAHsf6vjiwxi8urPGLD2t85BqjSHpI//795ff799htecuWLRo0aJBHVaE7rr76ar3yyit64403NGzYMPfyQYMGKRaLqa6ursPtOcb5acmSJdq6dauOPvpoBQIBBQIBzZ8/X3PmzFEgEFBNTQ3Hs4AMHjxYhx9+eIfLDjvsMK1du1aS3GPG3+DCceONN+qHP/yhLr30Uo0dO1bf/OY3df3112v27NmSOKaFLpPjN2jQoD0230skEtq5cyfHGHmDNX5xYH1fPFjjFxfW+MWHNX7xytf1PcF2DwmFQjrmmGM0b9489zLLsjRv3jxNnDjRw8qQKdu2dfXVV+uFF17Q3/72N40cObLD9cccc4yCwWCHY7xs2TKtXbuWY5yHTjvtNC1dulQffvih+zZ+/HhNmzbN/ZjjWTgmTZqkZcuWdbhs+fLlOuCAAyRJI0eO1KBBgzocz4aGBi1atIjjmadaWlrk83Vchvj9flmWJYljWugyOX4TJ05UXV2dlixZ4t7mb3/7myzL0oQJE3JeM9AZ1viFjfV98WGNX1xY4xcf1vjFK2/X91nZkrKXeuqpp+xwOGw/9thj9qeffmrPmDHDrqqqsjdv3ux1acjA9773PbuystJ+88037U2bNrlvLS0t7m2++93v2sOHD7f/9re/2YsXL7YnTpxoT5w40cOqsT/Sd0y3bY5nIXn33XftQCBg/+QnP7FXrFhh//73v7dLS0vt3/3ud+5t7r33Xruqqsp+6aWX7H/84x/2ueeea48cOdJubW31sHLszfTp0+2hQ4far7zyir1q1Sr7f/7nf+z+/fvbN910k3sbjml+a2xstD/44AP7gw8+sCXZ999/v/3BBx/Ya9assW07s+N3xhln2EcddZS9aNEi+6233rIPPvhg+7LLLvPqIQGdYo1fuFjf9w6s8QsXa/ziwxq/sBXi+p5gu4f98pe/tIcPH26HQiH7uOOOs9955x2vS0KGJHX69uijj7q3aW1ttb///e/bffv2tUtLS+3zzz/f3rRpk3dFY7/svujleBaWl19+2R4zZowdDoftQw891P71r3/d4XrLsuzbbrvNrqmpscPhsH3aaafZy5Yt86hadKWhocG+9tpr7eHDh9uRSMQeNWqUfeutt9rRaNS9Dcc0v73xxhud/rs5ffp027YzO347duywL7vsMrusrMyuqKiwv/3tb9uNjY0ePBpg31jjFybW970Da/zCxhq/uLDGL2yFuL43bNu2s9MLDgAAAAAAAABAz2PGNgAAAAAAAACgoBBsAwAAAAAAAAAKCsE2AAAAAAAAAKCgEGwDAAAAAAAAAAoKwTYAAAAAAAAAoKAQbAMAAAAAAAAACgrBNgAAAAAAAACgoBBsAwD05ptvyjAM1dXVeV0KAAAAgB7AGh9AsSPYBgAAAAAAAAAUFIJtAAAAAAAAAEBBIdgGgDxgWZZmz56tkSNHqqSkROPGjdNzzz0nqf0lhH/84x91xBFHKBKJ6Pjjj9fHH3/c4T6ef/55jR49WuFwWCNGjNB9993X4fpoNKp///d/V21trcLhsA466CD95je/6XCbJUuWaPz48SotLdUJJ5ygZcuWZfeBAwAAAEWKNT4AZBfBNgDkgdmzZ+vxxx/Xww8/rE8++UTXX3+9Lr/8cs2fP9+9zY033qj77rtP7733ngYMGKCzzz5b8XhcUnKxevHFF+vSSy/V0qVL9eMf/1i33XabHnvsMffrv/Wtb+nJJ5/UnDlz9Nlnn+mRRx5RWVlZhzpuvfVW3XfffVq8eLECgYCuvPLKnDx+AAAAoNiwxgeA7DJs27a9LgIAerNoNKrq6mq9/vrrmjhxonv5v/zLv6ilpUUzZszQ17/+dT311FO65JJLJEk7d+7UsGHD9Nhjj+niiy/WtGnTtG3bNv31r391v/6mm27SH//4R33yySdavny5DjnkEL322muaPHnyHjW8+eab+vrXv67XX39dp512miTpT3/6k6ZOnarW1lZFIpEsPwsAAABA8WCNDwDZR8c2AHjsiy++UEtLi77xjW+orKzMfXv88cf15ZdfurdLXxBXV1frkEMO0WeffSZJ+uyzzzRp0qQO9ztp0iStWLFCpmnqww8/lN/v1ymnnLLPWo444gj348GDB0uStm7d+pUfIwAAANCbsMYHgOwLeF0AAPR2TU1NkqQ//vGPGjp0aIfrwuFwh4Vvd5WUlGR0u2Aw6H5sGIak5GxAAAAAAJljjQ8A2UfHNgB47PDDD1c4HNbatWt10EEHdXirra11b/fOO++4H+/atUvLly/XYYcdJkk67LDD9Pbbb3e437fffltf+9rX5Pf7NXbsWFmW1WGeHwAAAIDsYI0PANlHxzYAeKy8vFw33HCDrr/+elmWpRNPPFH19fV6++23VVFRoQMOOECSdOedd6pfv36qqanRrbfeqv79++u8886TJP3gBz/Qscceq7vuukuXXHKJFi5cqF/96lf6j//4D0nSiBEjNH36dF155ZWaM2eOxo0bpzVr1mjr1q26+OKLvXroAAAAQFFijQ8A2UewDQB54K677tKAAQM0e/ZsrVy5UlVVVTr66KN1yy23uC8TvPfee3XttddqxYoVOvLII/Xyyy8rFApJko4++mg988wzuv3223XXXXdp8ODBuvPOO3XFFVe432Pu3Lm65ZZb9P3vf187duzQ8OHDdcstt3jxcAEAAICixxofALLLsG3b9roIAMDeObuZ79q1S1VVVV6XAwAAAOArYo0PAF8dM7YBAAAAAAAAAAWFYBsAAAAAAAAAUFAYRQIAAAAAAAAAKCh0bAMAAAAAAAAACgrBNgAAAAAAAACgoBBsAwAAAAAAAAAKCsE2AAAAAAAAAKCgEGwDAAAAAAAAAAoKwTYAAAAAAAAAoKAQbAMAAAAAAAAACgrBNgAAAAAAAACgoBBsAwAAAAAAAAAKyv8PQU0ytIuz308AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "# Imports\n", + "import csv\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "\n", + "path = \"project/models/benzene_dft_script/log.csv\"\n", + "\n", + "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", + "data_dict = {}\n", "\n", - "import matplotlib.pyplot as plt" + "with open(path, 'r') as file:\n", + " reader = csv.reader(file)\n", + "\n", + " # Extract the headers (keys) from the first row\n", + " headers = next(reader)\n", + "\n", + " # Initialize empty lists for each key\n", + " for header in headers:\n", + " data_dict[header] = []\n", + "\n", + " # Read the rest of the rows and append values to the corresponding key\n", + " for row in reader:\n", + " for idx, value in enumerate(row):\n", + " key = headers[idx]\n", + " data_dict[key].append(float(value))\n", + "\n", + "for key in keys:\n", + " fig, axes = plt.subplots(1, 2, sharey=True, sharex=True, figsize=(18, 4))\n", + "\n", + " val = np.array(data_dict[f\"val_{key}\"])\n", + " train = np.array(data_dict[f\"train_{key}\"])\n", + " epoch = np.array(data_dict[\"epoch\"])\n", + "\n", + " axes[0].plot(epoch, val)\n", + " axes[1].plot(epoch, train)\n", + "\n", + " axes[0].set_ylabel(f\"val_{key}\")\n", + " axes[0].set_xlabel(r\"epoch\")\n", + " axes[1].set_ylabel(f\"train_{key}\")\n", + " axes[1].set_xlabel(r\"epoch\")\n", + " fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Evaluation\n", - "==========\n", + "## Evaluation\n", "\n", "After the training is completed and we are satisfied with our choice of hyperparameters and vadliation loss, we can evaluate the model on the test set.\n", - "We provide a separate command for test set evaluation:\n", - "\n", - "`apax evaluate config_minimal.yaml`\n", + "We provide a separate command for test set evaluation:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!apax evaluate config_minimal.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "TODO pretty print results to the terminal\n", "\n", @@ -230,6 +459,37 @@ "cell_type": "markdown", "metadata": {}, "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To remove all the created files and clean up yor working directory run" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rm: cannot remove 'project': No such file or directory\n" + ] + } + ], + "source": [ + "!rm -r project config.yaml error_config.yaml" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 0d855bfecb43e5ce114ba3622a50b7e86e14f634 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 20:38:32 +0000 Subject: [PATCH 072/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/__init__.pyi | 2 +- tests/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/utils/__init__.pyi b/apax/utils/__init__.pyi index 289ae4ae..c87a369c 100644 --- a/apax/utils/__init__.pyi +++ b/apax/utils/__init__.pyi @@ -1,3 +1,3 @@ -from . import convert, data, jax_md_reduced, math, random, datasets +from . import convert, data, datasets, jax_md_reduced, math, random __all__ = ["convert", "data", "math", "random", "jax_md_reduced", datasets] diff --git a/tests/conftest.py b/tests/conftest.py index 184d2418..f76acc0a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,9 +12,9 @@ from apax.config.train_config import Config from apax.model.builder import ModelBuilder from apax.train.run import run -from apax.utils.random import seed_py_np_tf from apax.utils.datasets import download_md22_stachyose from apax.utils.helpers import mod_config +from apax.utils.random import seed_py_np_tf @pytest.fixture(autouse=True) def set_radom_seeds(): From d75e8147e6aeb4729f85815ef9a776996871fc25 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 21:45:58 +0100 Subject: [PATCH 073/192] Merge remote-tracking branch 'origin/moredocs' into moredocs-nico --- examples/01_Model_Training.ipynb | 179 ++++--------------------------- 1 file changed, 18 insertions(+), 161 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index ce166874..6611aa1f 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -45,49 +45,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1m \u001b[0m\n", - "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mapax [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m\n", - "\u001b[1m \u001b[0m\n", - "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-version\u001b[0m \u001b[1;32m-V\u001b[0m \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m Install completion for the current shell. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m Show completion for the current shell, to \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m copy it or customize the installation. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m \u001b[1;32m-h\u001b[0m Show this message and exit. \u001b[2m│\u001b[0m\n", - "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", - "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mdocs \u001b[0m\u001b[1;36m \u001b[0m Opens the documentation website in your browser. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36meval \u001b[0m\u001b[1;36m \u001b[0m Starts performing the evaluation of the test dataset with \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mvalidate \u001b[0m\u001b[1;36m \u001b[0m Validate training or MD config files. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mvisualize\u001b[0m\u001b[1;36m \u001b[0m Visualize a model based on a configuration file. A CO molecule is \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m taken as sample input (influences number of atoms, number of \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m species is set to 10). \u001b[2m│\u001b[0m\n", - "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "!apax -h" ] @@ -101,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -133,7 +93,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -169,18 +129,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32mSuccess!\u001b[0m\n", - "config.yaml is a valid training config.\n" - ] - } - ], + "outputs": [], "source": [ "!apax validate train config.yaml" ] @@ -195,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -210,21 +161,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 validation error for Config\n", - "n_epochs\n", - " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", - " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", - "\u001b[31mConfiguration Invalid!\u001b[0m\n" - ] - } - ], + "outputs": [], "source": [ "!apax validate train error_config.yaml" ] @@ -240,32 +179,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO | 21:25:29 | Initializing Callbacks\n", - "INFO | 21:25:29 | Initializing Loss Function\n", - "INFO | 21:25:29 | Initializing Metrics\n", - "INFO | 21:25:29 | Running Input Pipeline\n", - "INFO | 21:25:29 | Read data file project/benzene_mod.xyz\n", - "INFO | 21:25:29 | Loading data from project/benzene_mod.xyz\n", - "INFO | 21:25:39 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13445.14it/s]\n", - "INFO | 21:25:39 | Computing per element energy regression.\n", - "INFO | 21:25:45 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11969.02it/s]\n", - "INFO | 21:25:46 | Initializing Model\n", - "INFO | 21:25:46 | initializing 1 models\n", - "INFO | 21:25:53 | Initializing Optimizer\n", - "INFO | 21:25:53 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.87s/it, val_loss=0.63]\n" - ] - } - ], + "outputs": [], "source": [ "!apax train config.yaml" ] @@ -293,19 +209,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11786.22it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10499.15it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:44<00:00, 2.24s/it, val_loss=0.31]\n" - ] - } - ], + "outputs": [], "source": [ "from apax.train.run import run\n", "\n", @@ -329,50 +235,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWD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Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAA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3W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABboAAAFzCAYAAAD4yb97AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB0XUlEQVR4nO3dd3yV5f3/8ffZ52TvkISwkb0RBBxVcf8c1TqxUrT6dQ9qW7d1Ym2l1lGpWltrq9KqdUtFFBVFUZbsvSGLkJ2Ts+7fHyc5kiZgOCS5k5PX8/E4j8B97nPyObmiXOd9rvtzWQzDMAQAAAAAAAAAQCdlNbsAAAAAAAAAAAAOB0E3AAAAAAAAAKBTI+gGAAAAAAAAAHRqBN0AAAAAAAAAgE6NoBsAAAAAAAAA0KkRdAMAAAAAAAAAOjWCbgAAAAAAAABAp0bQDQAAAAAAAADo1OxmF9DeQqGQdu/ercTERFksFrPLAQAAQCsyDEOVlZXKzc2V1cqajq6COT4AAEBsOpT5fZcLunfv3q38/HyzywAAAEAb2rFjh7p37252GWgnzPEBAABiW0vm910u6E5MTJQU/uEkJSWZXA0AAABaU0VFhfLz8yNzPnQNzPEBAABi06HM77tc0N1wKWNSUhKTYAAAgBhF+4quhTk+AABAbGvJ/J7GhQAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATs1udgEAAAAA0Nl8ur5YlV6/jj0iU0luh9nlAAAAdHms6AYAAACAQ/SLfy3X9S8v1a59tWaXAgAAABF0AwAAAMAh8zjDb6Vq/UGTKwEAAIBE0A0AAAAAh8zjsEmSvD6CbgAAgI6AoBsAAAAADlFD0M2KbgAAgI6BoBsAAAAADpGboBsAAKBDIegGAAAAgEPkcdYH3bQuAQAA6BAIugEAAADgEEV6dLOiGwAAoEMg6AYAAACAQ0SPbgAAgI6FoBsAAAAADpE70rokZHIlAAAAkAi6AQAAAOCQsaIbAACgYyHoBgAAAIBDRI9uAACAjoWgGwAAAAAOkSfSuoSgGwAAoCMg6AYAAACAQ+SmdQkAAECHQtANAAAAAIeIHt0AAAAdC0E3AAAAABwijzP8Vooe3QAAAB0DQTcAAAAAHKLIim56dAMAAHQIBN0AAAAAcIjo0Q0AANCxdIig++mnn1avXr3kdrs1fvx4LVq06KDnP/744xowYIA8Ho/y8/N1yy23yOv1tlO1AAAAALo6enQDAAB0LKYH3bNnz9b06dN17733asmSJRoxYoROOeUUFRUVNXv+yy+/rNtuu0333nuv1qxZo7/85S+aPXu27rjjjnauHAAAAEBX5XGGg24vrUsAAAA6BNOD7pkzZ+rKK6/UtGnTNHjwYM2aNUtxcXF64YUXmj3/yy+/1KRJk3TJJZeoV69eOvnkk3XxxRf/4CpwAAAAAGgtrOgGAADoWEwNun0+nxYvXqzJkydHjlmtVk2ePFkLFy5s9jETJ07U4sWLI8H25s2b9f777+v0009vl5oBAAAAgB7dAAAAHYvdzG9eUlKiYDCo7OzsRsezs7O1du3aZh9zySWXqKSkREcffbQMw1AgENDVV199wNYldXV1qquri/y9oqKi9V4AAAAAgHbXEeb4kdYl/pBCIUNWq6XdawAAAMD3TG9dcqjmz5+vhx9+WH/605+0ZMkSvfHGG3rvvff0wAMPNHv+jBkzlJycHLnl5+e3c8UAAAAAWlNHmOM3tC6RpLpAqN2/PwAAABozNejOyMiQzWZTYWFho+OFhYXq1q1bs4+5++679dOf/lQ///nPNWzYMP34xz/Www8/rBkzZigUajrBvP3221VeXh657dixo01eCwAAAID20RHm+O79gm7alwAAAJjP1KDb6XRqzJgxmjdvXuRYKBTSvHnzNGHChGYfU1NTI6u1cdk2W3iSaRhGk/NdLpeSkpIa3QAAAAB0Xh1hjm+zWuS0h9+XEHQDAACYz9Qe3ZI0ffp0TZ06VWPHjtW4ceP0+OOPq7q6WtOmTZMkXXbZZcrLy9OMGTMkSWeeeaZmzpypUaNGafz48dq4caPuvvtunXnmmZHAGwAAAADamsdhky8QUq2PoBsAAMBspgfdF154oYqLi3XPPfeooKBAI0eO1Jw5cyIbVG7fvr3RCu677rpLFotFd911l3bt2qXMzEydeeaZeuihh8x6CQAAAAC6II/DpvJav7ys6AYAADCdxWiu30cMq6ioUHJyssrLy2ljAgAAEGOY63VNZo378b+fry0l1fr31RN0ZK+0dvu+AAAAXcWhzPNM7dENAAAAAJ1Vw4aUtC4BAAAwH0E3AAAAAETB42AzSgAAgI6CoBsAAAAAouBxhld006MbAADAfATdAAAAABAFD61LAAAAOgyCbgAAAACIQqRHNyu6AQAATEfQDQAAAABR8BB0AwAAdBgE3QAAAAAQhUiPblqXAAAAmI6gGwAAAACiwIpuAACAjoOgGwAAAACiQI9uAACAjoOgGwAAAACi0NC6pNYXMrkSAAAAEHQDAAAAQBQaWpd4WdENAABgOoJuAAAAAIgCPboBAAA6DoJuAAAAAIiCO9K6hKAbAADAbATdAAAAABAFVnQDAAB0HATdAAAAABAFenQDAAB0HATdAAAAABAFjzP8dooV3QAAAOYj6AYAAACAKLgd9OgGAADoKAi6AQAAACAK9OgGAADoOAi6AQAAACAKHic9ugEAADoKgm4AAAAAiELDim5/0JA/GDK5GgAAgK6NoBsAAAAAotDQo1tiVTcAAIDZCLoBAAAAIAouu1UWS/jP9OkGAAAwF0E3AAAAAETBYrFE2pd4fbQuAQAAMBNBNwAAAABEqSHoZkU3AACAuQi6AQAAACBKboJuAACADoGgGwAAAACi5HHWB90+gm4AAAAzEXQDAAAAQJQiPbpZ0Q0AAGAqgm4AAAAAiBI9ugEAADoGgm4AAAAAiJKb1iUAAAAdAkE3AAAAAETJ4wi/pWJFNwAAgLkIugEAAAAgSvToBgAA6BgIugEAAAAgSh5alwAAAHQIBN0AAAAAECU3m1ECAAB0CATdAAAAABAlD0E3AABAh0DQDQAAAABRokc3AABAx0DQDQAAAABRokc3AABAx0DQDQAAAABRokc3AABAx0DQDQAAAABR+r5Hd8jkSgAAALo2gm4AAAAAiFJD6xIvrUsAAABMRdANAAAAAFHy0LoEAACgQyDoBgAAAIAo0aMbAACgYyDoBgAAAIAoNbQuqaV1CQAAgKkIugEAAAAgSg2tS7ys6AYAADAVQTcAAAAARIke3QAAAB0DQTcAAAAARMntDL+lqvUHZRiGydUAAAB0XQTdAAAAABClhhXdhiHVBUImVwMAANB1EXQDAAAAQJTc9UG3RJ9uAAAAMxF0AwAAAECUHDarHDaLJPp0AwAAmImgGwAAAAAOQ8Oq7lofQTcAAIBZCLoBAAAA4DA09OlmRTcAAIB5CLoBAAAA4DB4nOGgmx7dAAAA5iHoBgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABbYAAAFzCAYAAADi9V/1AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABOkklEQVR4nO3deXiU9b3//9c9e0I2whK2IKDWBRAXFBG3Hqmo/Ny/bgdbrD1y2uJxoeqp+tXWpWLby6W0HrTn26PHtu4etdrWVqnC0SIKLsUNUPZ9zZ7Mct/374+Z+84EAhliZu6ZyfNxXbmSzEwm75k7CR9e93veH8O2bVsAAAAAAAAAABQIn9cFAAAAAAAAAACwPwi2AQAAAAAAAAAFhWAbAAAAAAAAAFBQCLYBAAAAAAAAAAWFYBsAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAi2AQAAAAAAAAAFJeB1AdlmWZY2btyo8vJyGYbhdTkAAADoIbZtq7GxUUOGDJHPR79Gb8IaHwAAoDjtzxq/6IPtjRs3qra21usyAAAAkCXr1q3TsGHDvC4DOcQaHwAAoLhlssYv+mC7vLxcUvLJqKio8LgaAAAA9JSGhgbV1ta66z30HqzxAQAAitP+rPGLPth2XppYUVHBohcAAKAIMYqi92GNDwAAUNwyWeMzjBAAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAi2AQAAAAAAAAAFhWAbAAAAAAAAAFBQCLYBAAAAAAAAAAWFYBsAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAJeFwAAAAAA+Wx7U1SLV+9Sn7BfJx08wOtyAAAAIDq2AQAAAGCfPt3YoO/+bonu+dPnXpcCAACAFIJtAAAAANiHoD/536ZYwvS4EgAAADgItgEAAABgH0KB5H+b4qbtcSUAAABwEGwDAAAAwD6EA07HtuVxJQAAAHAQbAMAAADAPjgd2zGTYBsAACBfEGwDAAAAwD6E/HRsAwAA5BtPg+3Zs2fr2GOPVXl5uQYOHKjzzjtPy5Yt63CbtrY2zZw5U/369VNZWZkuvPBCbdmyxaOKAQAAAPQ2QUaRAAAA5B1Pg+358+dr5syZeuedd/Taa68pHo/r9NNPV3Nzs3ub66+/Xi+//LKeffZZzZ8/Xxs3btQFF1zgYdUAAAAAehO3Y9u0ZNtsIAkAAJAPAl5+81dffbXD54899pgGDhyoJUuW6OSTT1Z9fb1+85vf6IknntA//dM/SZIeffRRHXbYYXrnnXd0/PHHe1E2AAAAgF7EmbEtSXHTVihgeFgNAAAAJI+D7d3V19dLkqqrqyVJS5YsUTwe1+TJk93bHHrooRo+fLgWLlzYabAdjUYVjUbdzxsaGrJcNQAAAIBs8nqNH04LtmOm1SHoBgAAgDfyZkVmWZauu+46TZo0SWPGjJEkbd68WaFQSFVVVR1uW1NTo82bN3d6P7Nnz1ZlZaX7Vltbm+3SAQAAAGSR12t8ZxSJxJxtAACAfJE3wfbMmTP18ccf66mnnvpK93PzzTervr7efVu3bl0PVQgAAADAC16v8X0+QwFfcvwIwTYAAEB+yItRJFdffbVeeeUVLViwQMOGDXMvHzRokGKxmOrq6jp0bW/ZskWDBg3q9L7C4bDC4XC2SwYAAACQI/mwxg/6fUpYJsE2AABAnvC0Y9u2bV199dV64YUX9Le//U0jR47scP0xxxyjYDCoefPmuZctW7ZMa9eu1cSJE3NdLgAAAIBeypmrHTNNjysBAACA5HHH9syZM/XEE0/opZdeUnl5uTs3u7KyUiUlJaqsrNR3vvMdzZo1S9XV1aqoqNC//du/aeLEiZ1uHAkAAAAA2eAG2wnb40oAAAAgeRxsz507V5J06qmndrj80Ucf1RVXXCFJeuCBB+Tz+XThhRcqGo1qypQp+o//+I8cVwoAAACgN3M2kIyZjCIBAADIB54G27bddbdDJBLRQw89pIceeigHFQEAAADAnsJuxzbBNgAAQD7wdMY2AAAAABSCEME2AABAXiHYBgAAAIAuBP1sHgkAAJBPCLYBAAAAoAt0bAMAAOQXgm0AAAAA6EL75pFd7xMEAACA7CPYBgAAAIAu0LENAACQXwi2AQAAAKALBNsAAAD5hWAbAAAAALrQHmyzeSQAAEA+INgGAAAAgC60z9imYxsAACAfEGwDAAAAQBfcYJtRJAAAAHmBYBsAAAAAuuCOIjFtjysBAACARLANAAAAAF1i80gAAID8QrANAAAAAF0g2AYAAMgvBNsAAAAA0IX2zSNNjysBAACARLANAAAAAF2iYxsAACC/EGwDAAAAQBfcjm2CbQAAgLxAsA0AAAAAXXA6tuOm7XElAAAAkAi2AQAAAKBLTrAdpWMbAAAgLxBsAwAAAEAX2jePJNgGAADIBwTbAAAAANCF9s0jTY8rAQAAgESwDQAAAABdCrJ5JAAAQF4h2AYAAACALoQDjCIBAADIJwTbAAAAANAFZxRJPGF7XAkAAAAkgm0AAAAA6FKIjm0AAIC8QrANAAAAAF0IMWMbAAAgrxBsAwAAAEAXnI7tKME2AABAXiDYBgAAAIAuBN2ObdPjSgAAACARbAMAAABAl8LM2AYAAMgrBNsAAAAA0AVnFEnctD2uBAAAABLBNgAAAAB0ydk80rRsmRbhNgAAgNcItgEAAACgC07HtiTF2EASAADAcwTbAAAAANAFgm0AAID8QrANAAAAAF0I+Az346hpelgJAAAAJIJtAAAAAOiSYRhsIAkAAJBHCLYBAAAAIAPh1AaSjCIBAADwHsE2AAAAAGTA6dgm2AYAAPAewTYAAAAAZIBgGwAAIH8QbAMAAABABtxgm80jAQAAPEewDQAAAAAZCKZmbEfp2AYAAPAcwTYAAAAAZCCUCrbjpu1xJQAAACDYBgAAAIAMMGMbAAAgfxBsAwAAAEAGCLYBAADyB8E2AAAAAGQgzOaRAAAAeYNgGwAAAAAy4MzYpmMbAADAewTbAAAAAJCBIME2AABA3iDYBgAAAIAMuDO2TdvjSgAAAECwDQAAAAAZYPNIAACA/EGwDQAAAAAZINgGAADIHwTbAAAAAJABd/NI0/S4EgAAABBsAwAAAEAG6NgGAADIHwTbAAAAAJABt2ObYBsAAMBzBNsAAAAAkAG3Y9u0Pa4EAAAABNsAAAAAkAFGkQAAAOQPgm0AAAAAyED75pEE2wAAAF4j2AYAAACADLR3bJseVwIAAACCbQAAAADIAJtHAgAA5A+CbQAAAADIQPvmkQTbAAAAXiPYBgAAAIAMOMF2PGF7XAkAAAA8DbYXLFigs88+W0OGDJFhGHrxxRc7XH/FFVfIMIwOb2eccYY3xQIAAADo1ZxRJFE6tgEAADznabDd3NyscePG6aGHHtrrbc444wxt2rTJfXvyySdzWCEAAAAAJLVvHkmwDQAA4LWAl9/8zDPP1JlnnrnP24TDYQ0aNChHFQEAAABA59qDbdPjSgAAAOBpsJ2JN998UwMHDlTfvn31T//0T7r77rvVr1+/vd4+Go0qGo26nzc0NOSiTAAAAABZki9r/KCfzSMBAADyRV5vHnnGGWfo8ccf17x58/TTn/5U8+fP15lnninT3HuHxOzZs1VZWem+1dbW5rBiAAAAAD0tX9b4YUaRAAAA5A3Dtu282NLbMAy98MILOu+88/Z6m5UrV+rAAw/U66+/rtNOO63T23TWzVFbW6v6+npVVFT0dNkAAADwSENDgyorK1nn9QL5ssZfvqVRpz+wQNV9Qnr/tm/k7PsCAAD0Fvuzxs/7USTpRo0apf79++uLL77Ya7AdDocVDodzXBkAAACAbMmXNX7IT8c2AABAvsjrUSS7W79+vXbs2KHBgwd7XQoAAACAXibEKBIAAIC84WnHdlNTk7744gv381WrVunDDz9UdXW1qqurdccdd+jCCy/UoEGD9OWXX+qmm27SQQcdpClTpnhYNQAAAIDeyA22TUu2bcswDI8rAgAA6L08DbYXL16sr3/96+7ns2bNkiRNnz5dc+fO1T/+8Q/993//t+rq6jRkyBCdfvrpuuuuu/LiZYgAAAAAepegv/0FrzHTUjjg97AaAACA3s3TYPvUU0/Vvvau/Mtf/pLDagAAAABg78KBtGA7QbANAADgpYKasQ0AAAAAXgmldWzHzb036AAAACD7CLYBAAAAIAM+n6GALzlXmw0kAQAAvEWwDQAAAAAZcjeQJNgGAADwFME2AAAAAGTIDbZN0+NKAAAAejeCbQAAAADIUDA1ZztKxzYAAICnCLYBAAAAIEPOBpKMIgEAAPAWwTYAAAAAZCicGkUSN22PKwEAAOjdCLYBAAAAIENsHgkAAJAfCLYBAAAAIENsHgkAAJAfCLYBAAAAIEPM2AYAAMgPBNsAAAAAkKFgKtiOEmwDAAB4imAbAAAAADLEjG0AAID8QLANAAAAABlygu24aXtcCQAAQO9GsA0AAAAAGWrv2GbzSAAAAC8RbAMAAABAhsLO5pEmo0gAAAC8RLANAAAAABlixjYAAEB+INgGAAAAgAwF/QTbAAAA+YBgGwAAAAAy5HRsRxlFAgAA4CmCbQAAAADIkBNsxxO2x5UAAAD0bgTbAAAAAJChkLt5pOlxJQAAAL0bwTYAAAAAZIjNIwEAAPIDwTYAAAAAZChMsA0AAJAXCLYBAAAAIENBdxQJwTYAAICXCLYBAAAAIEOMIgEAAMgPBNsAAAAAkKH2zSNtjysBAADo3Qi2AQAAAGRNa2urWlpa3M/XrFmjBx98UH/96189rKr72ju2TY8rAQAA6N0ItgEAAABkzbnnnqvHH39cklRXV6cJEybovvvu07nnnqu5c+d6XN3+YxQJAABAfiDYBgAAAJA177//vk466SRJ0nPPPaeamhqtWbNGjz/+uObMmeNxdfvPDbbZPBIAAMBTBNsAAAAAsqalpUXl5eWSpL/+9a+64IIL5PP5dPzxx2vNmjUeV7f/3BnbdGwDAAB4imAbAAAAQNYcdNBBevHFF7Vu3Tr95S9/0emnny5J2rp1qyoqKjyubv8xigQAACA/EGwDAAAAyJrbb79dN9xwg0aMGKEJEyZo4sSJkpLd20cddZTH1e0/p2M7btoeVwIAANC7dSvYfv/997V06VL385deeknnnXeebrnlFsVisR4rDgAAAEBh+z//5/9o7dq1Wrx4sV599VX38tNOO00PPPCAh5V1j9OxHaVjGwAAwFPdCrb/9V//VcuXL5ckrVy5UpdeeqlKS0v17LPP6qabburRAgEAAAAUtkGDBumoo46Sz+dTQ0ODXnzxRZWXl+vQQw/1urT91j6KxPS4EgAAgN6tW8H28uXLdeSRR0qSnn32WZ188sl64okn9Nhjj+n555/vyfoAAAAAFLCLL75Yv/rVryRJra2tGj9+vC6++GIdccQRBfl/B3fzSJOObQAAAC91K9i2bVuWlVzIvf766zrrrLMkSbW1tdq+fXvPVQcAAACgoC1YsEAnnXSSJOmFF16Qbduqq6vTnDlzdPfdd3tc3f5j80gAAID80K1ge/z48br77rv129/+VvPnz9fUqVMlSatWrVJNTU2PFggAAACgcNXX16u6ulqS9Oqrr+rCCy9UaWmppk6dqhUrVnhc3f5zOrYtW0rQtQ0AAOCZbgXbDz74oN5//31dffXVuvXWW3XQQQdJkp577jmdcMIJPVogAAAAgMJVW1urhQsXqrm5Wa+++qpOP/10SdKuXbsUiUQ8rm7/OR3bkhQ3bQ8rAQAA6N0C3fmiI444QkuXLt3j8p///Ofy+/1fuSgAAAAAxeG6667TtGnTVFZWpgMOOECnnnqqpOSIkrFjx3pbXDekB9uxhKWSEP//AQAA8EK3gu1169bJMAwNGzZMkvTuu+/qiSee0OGHH64ZM2b0aIEAAAAACtf3v/99HXfccVq3bp2+8Y1vyOdLBsOjRo0qyBnbAZ8hw5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABA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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import csv\n", "import matplotlib.pyplot as plt\n", @@ -469,17 +334,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "rm: cannot remove 'project': No such file or directory\n" - ] - } - ], + "outputs": [], "source": [ "!rm -r project config.yaml error_config.yaml" ] From 99307a40b85ea7bf55159750681b0b7fb4b3bb33 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 1 Mar 2024 22:05:22 +0100 Subject: [PATCH 074/192] example 01 update --- examples/01_Model_Training.ipynb | 205 ++++++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 29 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 6611aa1f..46f0c786 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -26,8 +26,7 @@ "data_path = Path(\"project\")\n", "\n", "file_path = download_md17_benzene_DFT(data_path)\n", - "file_path = mod_md17(file_path)\n", - "\n" + "file_path = mod_md17(file_path)" ] }, { @@ -45,9 +44,49 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mapax [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-version\u001b[0m \u001b[1;32m-V\u001b[0m \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m Install completion for the current shell. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m Show completion for the current shell, to \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m copy it or customize the installation. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m \u001b[1;32m-h\u001b[0m Show this message and exit. \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mdocs \u001b[0m\u001b[1;36m \u001b[0m Opens the documentation website in your browser. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36meval \u001b[0m\u001b[1;36m \u001b[0m Starts performing the evaluation of the test dataset with \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvalidate \u001b[0m\u001b[1;36m \u001b[0m Validate training or MD config files. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvisualize\u001b[0m\u001b[1;36m \u001b[0m Visualize a model based on a configuration file. A CO molecule is \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m taken as sample input (influences number of atoms, number of \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m species is set to 10). \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\n" + ] + } + ], "source": [ "!apax -h" ] @@ -61,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -93,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -116,7 +155,7 @@ "config_dict = mod_config(config_path, config_updates)\n", "\n", "with open(\"config.yaml\", \"w\") as conf:\n", - " yaml.dump(config_dict, conf, default_flow_style=False)\n" + " yaml.dump(config_dict, conf, default_flow_style=False)" ] }, { @@ -129,9 +168,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "config.yaml is a valid training config.\n" + ] + } + ], "source": [ "!apax validate train config.yaml" ] @@ -146,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -161,9 +209,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 validation error for Config\n", + "n_epochs\n", + " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", + " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", + "\u001b[31mConfiguration Invalid!\u001b[0m\n" + ] + } + ], "source": [ "!apax validate train error_config.yaml" ] @@ -179,9 +239,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 21:56:40 | Initializing Callbacks\n", + "INFO | 21:56:40 | Initializing Loss Function\n", + "INFO | 21:56:40 | Initializing Metrics\n", + "INFO | 21:56:40 | Running Input Pipeline\n", + "INFO | 21:56:40 | Read data file project/benzene_mod.xyz\n", + "INFO | 21:56:40 | Loading data from project/benzene_mod.xyz\n", + "INFO | 21:56:50 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13135.40it/s]\n", + "INFO | 21:56:50 | Computing per element energy regression.\n", + "INFO | 21:56:57 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12868.33it/s]\n", + "INFO | 21:56:57 | Initializing Model\n", + "INFO | 21:56:58 | initializing 1 models\n", + "INFO | 21:57:04 | Initializing Optimizer\n", + "INFO | 21:57:04 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" + ] + } + ], "source": [ "!apax train config.yaml" ] @@ -209,9 +292,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 10410.16it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11413.38it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:43<00:00, 2.24s/it, val_loss=0.31]\n" + ] + } + ], "source": [ "from apax.train.run import run\n", "\n", @@ -235,9 +328,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWDZLda9NGiHD3w5Srtqely7pQSo80FFbJbLfrXeQN01qCM/X4ftfOrc0uqdeO4bpow+rdO7YYoqfRo5vp8ZSRGqX9mQqOu0Zqxzjtyce8BAADCE6E1AABokG9W5OrPbyyUJD3yh/76XY80vTZ7s/47Z6tKq72SpPR4p565aLCGdtw3+K0Pt9ev4kq38spc2l1ardzSau0uCfy4q6RaK3JKggFxfUTYLLrvjL66aHj2fh/3+w298stmPfzN2uDIj8HZibp6TGed0LutbFaLZq0v0JX/mS+XN9Bh/cz4wXXC4aIKt6Z+tVrv13RPRztsevbiITq2+8E3evT7Dbm8fkU5zBmtEQ5Y5x25uPcAAADhidAaAIAwsHxHiZ6ZsUFnDWqvk/u2a7bXWbe7TGc/84sq3D5dPrKj7j2jT/CxcpdXb8/bppdmbdLuUpeSYxz67PrRykiMOug131uwXd+uyFVhhVt7Kt0qqnCrrCb8PhiHzao+GfEamJWogVmJ6tM+QRUur3YWVymn5mtncWAzwb/8rquGdDj0yI2N+eV6YeYmfbw4Jxhed0iO1hkD2uuFnzbJ5fVrXK90/d/4wXLY99/NPHdToT5ZnKOLj+6gvhkJh3xNHD7WeUcu7j0AAEB4IrQGAKCV25RfrnOfnR3sPD5rYHvdd0ZfJUTvfxO/g1m0bY9KKj0a1TVln1C2pNKjM5+ZpS2FlRrROVmvXzlsv2Moqtw+nfvsbK3aVap+GQl6/88jDrhB34s/bdKDX63e72MWi5Qc41TbBKfaxkcqPT4y8GNCpLqnx6lXu7hmG0GSV1at12dv1X/nblVJ1W8d3cf3TNOzFw9u1tEnaDjWeUcu7j0AAEB4IrQGAKAVyy9z6dxnZ2tbUaUyEqO0q6RKfkNqGx+pf/6h/yFHU+xt2Y5inf1/s+XzG0qMjtDv+7fT2YMyNTg7UX5DmvDafM1cF5ib/Nl1o5Qc6zzgtbYXVer0p2epuNKjcwdn6l/n9d9nc8M35m7V3z5ZIUmaMKqTju6cpKQYh9rEOJQU7VB8VIRsJm8gWOn26v0FO/TWvG3q0TZOj5zXn8A6BLHOO3Jx7wEAAMIToTUAAC3kvQXb9dXyXWqfGKWsNtHKTvrtqzFd0ZVury54Ya6W7ShRdlK0PvzLSO3YU6lb3luqTQUVkqTxw7P111N7KcZpP+i1qj0+/f6pWdqQVy6HzRocjSFJHZOj1SklRjPW5isywqoP/jyyXmMvZq0v0KWvzJPfkO47o48uG9kx+NjHi3fo5veWyjCkv/yui+44uWeDv3+gFuu8Ixf3HgAAIDw1ZJ138H/tAgCAA/ppXb7u/HCZ/Ad4+7dn2zg9fdFgdU2Lrdf1vD6/rntrsZbtKFGb6Ai9dsVRSo1zKjXOqS9vOEb//GaNXpu9RW/O26af1xfolcuHqmta3AGv99i0ddqQV67UOKe+nnSMVu8q1UeLcvTNilxtKazUlsJKSdI/z+1f7znNo7ulaPIpvfTgV6t1/xer1LNtnIZ3TtY3K3J16/vLZBjSZSM66PaTetTregAAAAAA/C86rQEAhyWnuEob8so1skvyfmchh6u9R2Wc1CddPdLjtK2oUtv3VGlbUaXyy1ySpLhIu/5v/GAd0+3gIz0Mw9BfP16ut3/dLqfdqreuOnq/mwzO3lCg2z5YppziKqXFOfXuNSPUKSVmn/MWbCnSec/PkWFIL106VON6pwcfq3B59e3KXH2zIldHd07WhNGdGvS9G4ahSe8s0WdLdyo5xqE7Tu6puz5ZLo/P0B+GZOrhc/vLavIIELR+rPOOXNx7AACA8MR4EAA4Qr36y2bll7l00wndWyRALq326MTHflJuabXaxkfq0pEddNGwbCVGO5r9tc1U7QlsSrhyZ6n6ZybovWv23ZQwv8ylv7yxUAu27pHNatE9p/fWpSM6HvCaT01fr0enrZPVIj138RCd2KftAc/dU+HWhS/O1ZrcMrVLiNS7V49QdnJ08PFKt1en/vtnbSms1LmDM/XoHwcc9vf8v6rcPp3z7Gyt3lUaPHZa/3Z68oJBps+sRnhgnXfk4t4DAACEp4as846cljgACHMfL96h+z5fpf/7caMmf7RcLfGe5D+/XqPc0mpJUm5ptR7+Zq2Onjpdd328XBvyyut9HY/Pr6+W79KOPZX1On/66t3617drVVrtaVTdB1Ll9mnW+gK9+stmrd9dtt9zDMPQXR+v0MqdpUqKcejZi4fsE1hLUmqcU29eNVznDM6Qz2/o7k9X6u5PV8i711zpncVVem7mRp38xE96dNo6SdK9Z/Q5aGAtSW1iHHrjT8PVNS1Wu0qqdeGLc+v83j38zVptKaxU2/hI3X1678b8VhxSlMOmFy4ZosSaud3H90zT438cSGANAAAAADhsdFoDQBjYXFCh3z/5syrcvuCxG8d1043jujfba87fUqTznpsjSXrtiqNUUO7Wy7M21+287ddOD/+h/0E3DPT6/Lr+7cX6ekWuIiOsmjS2u/50TKf9dooXlLt0z2cr9eWyXZKkkV2S9doVw+SwN+492AqXVwu37tHcTYWat7lIy3YUy+ML/G/RapH+MCRTN53QXe0SooLP+e/crZryyQpZLdIbVw7XyK4pB30NwzD03MxNevjbNTIM6ZhuKTq1Xzt9uiRH8zYXqfb/whE2i244vpuuH9ut3vXnlVbrghfmalNBhbKTovXuNUdrc0GFLnpxniTpPxOG6djuBx9Lcrg25JVpzsZCnTc0a7/hPdBYrPOOXNx7AACA8MR4EAA4gri9fp377GwtzynR8E5J+v2A9pryyQpJ0iN/6K/zhmY1+Wu6vD6d+u+ftTG/Qn8cmqmH/xAYP2EYhuZtLtIrszZr2urdMgxpUHaiXr38qP2ODPH5Dd383hJ9umRnneM90uP0j3P6akiHpOB1P1+2S/d+tlJFFW7ZrBZF2Cyq9vh1zuAMPXreAFks9e/wLany6PmZG/XqL1tU5fHVeaxdQqQy20Rp/pY9kiSn3arLR3XUtcd21Yb8cl3wwhx5fIYmn9JT1xzbpd6v+e3KXN34zpJ9Xm9YpySdNTBDp/Zr26ixKrkl1frj83O0rahSnVJi5Pb6lVNcpQuHZWvqOf0afD0gVLDOO3Jx7wEAAMIToTUAhIBfNxfJabdqQFZis77OA1+s0kuzNisxOkJfTzpG7RKi9PA3a/R/P26U3WrRq1ccdchNABvq8Wnr9O/p65US69T3N4/Zb9i6aNseTXhtvoorPeqRHqf/XjlMafGRwcf9fkN3frRM7y3YIbvVomcvHqKyao8e+HK1iirckqQLh2VpwqhOevjbtZq2arckqWfbOD3yhwEqrHDpyv8skM9vaNLYbrrphEN3lVd7fHp9zhY9M2OjSqoCo0UyEqM0vHOSju6UrKM7JysrKUoWi0ULt+7RP79eo1+3FEmS4iPtctitKih369R+bfXMRYMbFJRL0oqcEk16Z7EibFadMbC9zhjQXpltog/9xEPYsadS5z8/VznFVZKkzDZR+ubGMYo9SIc7EOpY5x25uPcAAADhidAaAEy2IqdEpz89SxE2q2be9rs64yWa0oy1ebri1fmSpBcvHaoTeqdLCgTCN9V0MMc67Xr/zyPUq92h/56sdHv13MxN+mRxjs4Y0F7XHd91n5EP63eX6dQnf5bHZ+jpiwbp9/3bH/B6a3PLdMnL85RX5lKH5Gi9ceVwZSVFyzACM57/O3errBbpqQsH67T+7SQFNhl86Os1enfB9jrXslstuu74rrr2d12D40De/nWbJn+0XNLBu8q9Pr8+XLRDT3y/XrtKAjO4u6XF6raTeuiE3ukHDJ8Nw9APa/L08DdrtbZmxnW3tFh9PHFUyAXC2wordf4Lc1RQ7tLrE4ZrRJdks0sCDgvrvCMX9x4AACA8EVoDgIkMw9D5z88NduheOqKD/n5m34M+Z3tRpf75zRqN65WuswZl1Ot18kqrdcq/f1ZhhVuXj+yoe8/oU+dxl9eny175VXM3FaltfKQ+njjygOG532/ow0U79Mi3a5VX5goe75QSowfP7quRXVKC5533/Bwt3LpHY3um6aXLhh6y23hbYaXGvzxX24uqlB7v1BtXDtd7C7brxZ83y2KRHvvjAJ09KHOf5/26uUh/rdnQsW9GvB75w4D9Bu97d5W/dsUwje7224zpdbvL9PnSnfp0yU5tKwpsVNg+IVI3ndBd5wzOrPemgT6/oY8X52j2xgLdOLa7spMPvzu6OVS5fSqqdCsjsXneJAFaEuu8Ixf3HgAAIDwRWgMhoMrt07VvLlT39DhNPrWX2eWEDI/Pr48X5yirTbSO7pzU4PEKZvrP7C16Z/52PX7+APVse+C/c75avkvXvrlIdqtFXr8hh82qH2/7ndofIEg0DEMXvThPczYVSpLOGZShv5/V96CdvH6/oUtf+VWzNhSoV7t4fXztyP1ugldS6dEfnput9XnlinHYNKRjkoZ3StLRnZPULyNRDrtVczcV6v4vVmnlzsAGillJUbrgqGy9PmeLdpcGAuzzhmTqr6f20hfLdmrKpysV47Bp2s3HHvB7+l+7S6t1ycvztG53uZx2q1xevyTpoXP66YJh2Qd8ntvr1+pdperTPl72/WzMWPt7ceO7S/TZ0p2Kc9r15EWDtDKnRJ8v3RXsjpakNtERmnhcV118dAc2DARaAdZ5Ry7uPQAAQHgitAZCwJfLdmniW4skSa9efpSO65lmckXmMwxDt7y/VB8typEk9W4XrwmjO+n0Ae3ktId2iJhbUq1jH5khl9evTikx+uy6UYqLjNjnvGqPT+Mem6kde6o0aWw3zd1UqHmbi3Tx0dl64Kz9b4pXG3I7bFZ5/X75jUCH81MXDlLfjIR9zt+QV67nZ27U+wt3KCrCpi9uGK0uqbEHrH3Hnkpd8vKv2lxQUed4VIRNnVJitGpXIKyOc9p13fFdddnIjoqMsKm02qNHvlmrN+ZtlWFIyTEOubx+lbu8uvf03rp8VKeG/BZqT4Vbl782X0u3F0uS7jujjy4b2bFB1zgQl9enS176NdjdXivCZtGx3dN0+oB2GtcrXTEhNtIDwIGxzjtyce8BAADCE6E1EAJueW+pPly0Q5LUITla39445ojv7pz69Wo9P3OTbFaLImwWVXsC3bYpsU5dcnQHXXx0tpJjnSZXuX+TP1qut3/dFvz1af3a6emLBu3TKf5/P27Qw9+sVdv4SP1w67FatqNEF7wwVxE2i2bedtw+nclV7kDInVMcCLlHdU3RpHcWa1dJtRw2q+48paeuGNVRlW6fvly2S+8u2K6FW/cEn//wH/rrjweY47w3n9/QmtxSzdtUpHmbC/Xr5iLtqQxsRGi1SBcNz9ZN47rv9/d/4dYiTf5oudbtLpckDcxK1Id/GVnv0Rp7K3d59eT09erVLm6/I0EOR3GlW+c/P1cb8ss1skuyTh/QXif1bquE6H3fXAAQ+ljnHbm49wAAAOGJ0Bowmd9v6KgHv1dhhVsOu1Vur183n9BdN4ztZnZppnnp50164MvVkgIb5p3QO11v/bpNr8/eqtzSwMZ4DrtV/zy3X5OHmftT7vLqgwXb9dXyXF04POugr7kpv1wnPP6TfH5Dd53aS//8Zo28fmOfTuG8smod/6+ZKnd59fj5v81pvvCFuZqzqVDjh2frwbPrdls/Nm2dnpy+XhmJUfr+5mMV5bCpuNKt2z5YpmmrdkuS+mcmaGNeuSrcPkmSzWrRcT1SdfHRHfS7Ho3r4Pf7Da3PK9fKnSXqn5mormkH7tSWAmM6Xvx5k+ZuKtR9Z/RR54N0dpvJ7fXL7fOH3CaJABqOdd6Ri3sPAAAQnhqyzuNf9UAzWLqjWIUVbsU57br3jD665f2lembGBp09KENZSaG5gduheH2BMNBqsTS4Y/yTxTnBwPqOk3vqvJrO4Gt/11VXHdNZXy3fpVdmbdbSHSW648Pl6pEer97tm+cfqdsKK/Xa7C16f8F2lbm8kqTF2/eoS2qs+mcm7vc5j05bJ5/f0NieabpqTGdZrRbd/8UqPfDlKg3MStSArMDzHvtuncpdXg3IStSZA37bTPHGcd0054VCvbdgu/7yuy7KbBP4M7C9qFLPzdwoSfrbab0U5Qj8viZGO/TCJUP037lb9cAXq7VsR4kkqWNytP54VJb+MDhTafGRh/X7YLVa1KNtnHq0javX+Q67VROP66qJx3U9rNdtbg67VQ77/mdfAwAAAACA1oHQGmgGM9bkSZKO6Z6icwZn6IOFOzRnU6Hu+3ylXrrsKJOrO7Svl+/SP79Zo+Iqj1yeQFjt8wc+lGG3WjS8c5JO6JWucb3TgwHsgcxcl69b318qSbpydCf9+djOdR6PsFl15sAMnd6/va78z3zNWJuv695apM+uH33Ablm/39Aj363V0u3FevDsfuqUEnPI72n+liK98NMmfb96t2o/X9I5NUZJ0Q4t2LpH1721WF/cMFrx/zOnekVOib5ctksWi3TrST0kSRNGddT8zUX6ZmWurn1zkb664RjtKK7Uuwu2S5Lu/n1vWfcanTG8c7JGdknW7I2F+r8fN+ofNd3WD3y5Sm6vXyO7JOvkvm3rvK7FYtGlIzrqqI5J+nzpTo3pnqrhnVrXxpUAAAAAAACNQWgNNIMf1gZC6+N6pMlisej+s/ro5Cd+1ver8/T9qt0a1zvd5AoPbPG2PZr0zhK5ff79Pu71G/plQ6F+2VCoez9fpd7t4jWud7qO6thG0Q6bnHabIiNsioywantRlf7yxkJ5/YbOHNhed53a64Chq9Vq0aN/HKhT//2zNhVU6G8fL9fj5w/c53yf39AdHy7TBwsD88LPe262/jNhmPq033fDQikQcD/x/To9+cOG4LEx3VM1YVRHjemWqjKXV6f++2dtK6rUXz9arqcurDun+uFv10qSzhqYoV7tAt3fFotFD5/XX6t2lWpbUaVueX+Jyl1eGYZ0xoD2GtKhzT513Diuu2ZvnKP3F2zXtb/ros0FFfp25W7ZrBbde0afA/6+9GoXH3xdAAAAAACAIwGhNdDEdpdWa0VOqSQF5w13TYvTlcd00vMzN+m+L1ZqdLeUZtmU0TAM/Wf2FkU5bDr/qOwGPz+vtFp/fmOh3D6/TuidrttP6iGn3SZnhFUOm1XOCKtyS6o1fXWepq3arQVbi7RqV6lW7So96HWP6ZaiR/4woE738f4kxTj01EWDdMELc/XJkp0a0SW5zvfh8xu67f2l+mhxjqwWKTspWlsKK3XB83P18uVHaVinpDrXq3R7dfO7S/XNylxJ0nlDMnXNsZ3VNe23kRgJURF66qJB+uNzc/TFsl0a1TVFFw4LvObsjQX6aV2+ImwW3TSue51rx0dG6P/GD9Y5z87W96sDb1I47VbdcUrP/X5vwzolaVTXZP2yoVBPfL9ei7cFNlO8dEQHdU+v34gOAAAAAACAIwGDP4EmVjsaZEBWolLjnMHjNxzfTW3jI7W9qErP/rixWV77kW/X6t7PV+mOD5fr6+W7GvRcl9enP7+xULtLXeqWFqvHzx+obulxyk6OVnp8pNrEOBTtsKtzaqyuGtNZ7/15hObfNU7/Om+ATu7TVt3TY5WdFK20OKfiI+3BucLHdk/VcxcPqfec4aM6JumWEwMB8d2frtSa3EAg7vX5dfN7S/TR4hzZrBY9eeEgfXb9aA3rmKQyl1eXvDxP01fvDl4np7hKf3h2jr5ZmSuHzap/nTdAj5w3oE5gXWtwdpvg6I97P1uptbllMgxDD38T6LK+aFi2spP3HYPSNyNB95zeO/jra8Z0VkZi1AG/t9rg+4OFO7Qxv0LJMQ7d+D9hOAAAAAAAwJHO1E7re++9V/fdd1+dYz169NCaNWtMqgg4fD/UhNbH13RZ14px2jXl97018a1FenbmRnVOjZHL41dhhVuF5S4VVbi1p9Itt88vj9eQx++X12fI4/MrISpCk0/tpYE1G/7tzxtzt+r/9grD//rxcg3p0KZeG/YZhqF7Pl2pRduKFR9p14uXDj3gPOm9Jcc69YchmfrDkMwDXrcxM5j/PKaL5m0q0sx1+Zr45iJ9dO0o/fXj5fpy2S7ZrRY9deEgndKvnSTp9SuHaeKbizR9TZ6u/u9C/eu8/spOitY1/12ognK3UmIdev6SIRrSIemgr3n1MZ01e2OhfloXmKl93fFdtWR7saIdNl13fLcDPu+iYdnasadKm/LLdc2xXQ76GkM7JumYbin6eX2BJOn2k3soISrioM8BAAAAAAA40lgMo3ZLspZ377336oMPPtD3338fPGa325WSklKv55eWliohIUElJSWKj2fmK8zn8vo06O/TVOn26fPrRqtfZt05y4Zh6JKXf9WsDQUNvrbDbtU/z+2nswftGxB/v2q3rv7vAvkN6frju+qHNXlaubNUx/VI1SuXH3XI4Pi/c7dqyicrZLVIr1x+VHCsiZkKy1069cmftbvUpZRYhwrK3YqwWfTMRYN1Yp+6mxZ6fH7d/sEyfbw4R5IUYbPI4zPUq128Xrps6EG7n/dWUO7Sqf/+WXllLlktkt+Qrjuua7ALuyks2V6s856brQGZiXrvmhGHHJkCAEcq1nlHLu49AABAeGrIOs/0mdZ2u11t27Y99IlAK/Dr5iJVun1KjXOqT/t9/+OzWCx68Oy+mvTOEvkNQ0kxDiXHOJUc61ByjENtoh1yRlgVYbPKbrUEfrRZ9J/ZW/X96t266d2lWpNbpttP6ilbTdi5dHuxrn97sfyGdP7QLN18QnedPqC9fv/ULM1Ym6+3ft2m8cM7HLDmeZsKdd9nKyVJt5/cMyQCaynQxf3kBYN04YtzVVDulsNm1bMXD9bYXvtuYhlhs+rR8wYoMTpCr/6yRR6foVP6ttWjfxygaEf9/5pLiXXqifMHavzL8+Q3pMToCF19bOem/LY0MCtRP99+vBKjIwisAQAAAAAA9sP00Hr9+vVq3769IiMjNWLECE2dOlXZ2fvfQM7lcsnlcgV/XVp68M3fgJY2ffVvo0EOFEh2SI7RJxNHNei6o7qk6NFpa/XMjI16fuYmrd9drn9fMFB7Kjy68j/zVeXx6djuqXrg7L6yWCzqnh6n20/qoQe+XK0HvlitUV1S1DElZp/rLttRrGvfXCSv39AZA9rrmjFNG9AeruGdk3X/WX31n9lbNPnUXjruIIG61WrR3b/vrb7tE+T2+XX+0KxGhcIju6bo1hN76JFv1+rWE3soPrLpx3e0TTj0yBYAAI4UrPEBAADwv0wdD/L111+rvLxcPXr00K5du3TfffcpJydHK1asUFzcvpul7W8GtiQ+OoiQYBiGfvevH7W1sFLPXTxEJ/dt+k8QfLokR7d/sEwur19d02Ll8xvaXFChPu3j9e41I+rMofb7DY1/aZ7mbCrUoOxEvX/NCNltgc0QC8pd+te3a/Xugu0yDKl3u3h9+JeRinLYmrzm1qq02tMsgTUAoH4YEXHkYI0PAABwZGjIGt/U0Pp/FRcXq0OHDnrsscd05ZVX7vP4/rowsrKyWNAiJGzML9fYR2cqwmbR4rtPrNdGho2xbEexrn59oXJLqyVJGYlR+vjakfvdcDGnuEonP/6Tylxe3Xpid11zbBe9MXerHpu2TmXVXknS2YMydNdpvZQS62yWegEAaAxC6yMHa3wAAIAjQ6uaab23xMREde/eXRs2bNjv406nU04nwRpC04w1gdEgwzslN1tgLUn9MxP12XWjNOmdJdq+p1KvXXHUfgNrKRBo33dmH9383lI98f16fbJkpzbklUuS+rSP131n9NHQjknNVisAAMChsMYHAADA/wqp0Lq8vFwbN27UJZdcYnYpaMV27KlUZIStxTuHf6gJrY/v2fwbGabFR+rtq4+WYRiyWA4+t/nsQRn6fvVufbU8VxvyytUmOkK3ndRT5x+VFdzMEQAAAAAAAAgVpobWt956q04//XR16NBBO3fu1D333CObzaYLL7zQzLLQiu0srtKJj/+kyAibPvrLyP1uPtgcSqs9+nVzkaSWCa1rHSqwrj3nwbP6ye+XMtpE6frjuyox2tEC1QEAAAAAAAANZ2povWPHDl144YUqLCxUamqqRo8erblz5yo1NdXMstCKvTF3qyrdPlW6fZrwn/n6+C+jlBDd/JvpzVpfIK/fUOeUmBYLyhuiTYxDz10yxOwyAAAAAAAAgEMyNbR+5513zHx5hJlqj09v/7pNkhQVYdOm/ApNfGuRXr3iKEXYrA26lmEYqnD76j2bunY0yHEt2GUNAAAAAAAAhKOGJXlACPt0SY72VHqUkRil964ZoWiHTbM2FOiez1bKMIx6X2d7UaUufnme+t37rR78cpU8Pv9Bz1+2o1jTVu2WJI0ltAYAAAAAAAAOC6E1woJhGHr1ly2SpMtGdlC/zAT9+4JBslikt+ZtCz52MH6/of/O2aKTnvhJv2wolGFIL/68WRe9OFe7S6v3+5r/nbNFf3h2jkqqPOqeHquhHZOa+DsDAAAAAAAAjiyE1ggZ87cUafxLc7VqZ2mDnztvc5HW5JYpKsKm84dmS5JO6J2uv57SS5L0wJer9MOa3Qd8/vaiSo1/aZ6mfLpSlW6fhnVK0oNn91Wc0675W/botCd/1uyNBcHzy11e3fDOEk35dKXcPr9O7J2u9/88Ug47/0kBAAAAAAAAh8PUmdZALcMwdO9nK7VyZ6kmf7xcn1w7UhaLpd7Pf/WXzZKkcwZn1Nl48U/HdNLG/HK9M3+7rn9rse46rbdiI+1y2CyyW62KsFu1fneZHpu2TpVun6IibLrzlJ665OgOslotGtklRX95Y6HW5Jbp4pfm6ZYTe+j4nmma+OYibSqokN1q0Z2n9NSVozs1qF4AAAAAAAAA+0dojZAwb3ORVtZ0WC/dXqyvlufqtP7t6vXc7UWVwZnSl4/sWOcxi8Wi+8/qq21FlZq9sVB//Xj5Aa8zvFOSHvnDAGUnRwePdUqJ0cfXjtKUT1fog4U79Mi3a/Wv79bKMKR2CZF6+qJBGtKBkSAAAAAAAABAUyG0Rkh4ZVagU7pNdIT2VHr0yLdrdGKfdEXYDj1u4425W+U3pNFdU9QtPW6fxyNsVj07foj+9d1abS2qlMfrl9fvl9tnyOP1y2a16Lyhmbp4eKC7+n9FOWx65A/9NbRDG9392Uq5vX6N6Z6qJ84fqKQYx+F/8wAAAAAAAACCCK1hum2FlZq2OtAp/doVw3Tlf+ZrS2Gl3v51my4d0fGgz610e/X2r9skSVeMOvC5CdERuv+svo2u0WKx6IJh2RraMUkb8sp0Yu+2+w24AQAAAAAAABwedo2D6V6bvUWGIR3bPVUDshI1aWw3SdKT09er3OU96HM/Xpyj0mqvOiRH67geac1ea9e0WJ3ctx2BNQAAAAAAANBMCK1hqrJqj95bsF2SNGF0J0nSBcOy1SklRgXlbr3406YDPtcwDL32yxZJ0qUjOhIkAwAAAAAAAGGA0Bqmen/BDpW7vOqaFqsx3VIkBWZQ33ZSD0nSiz9vUl5Z9X6fO3tjodbnlSvGYdN5QzNbrGYAAAAAAAAAzYfQGqbx+Q29NnuLpMA8aovlt07pU/q21YCsRFW6fXpy+vp9nru1sEKPTVsnSfrDkEzFR0a0SM0AAAAAAAAAmhehNUwzffVubSuqVEJUhM4ZVLdT2mKxaPIpPSVJb/+6XZvyyyVJS7cXa+Kbi3Tcv37Uwq175LBZdenIji1dOgAAAAAAAIBmYje7ABy5XvllsyTpouHZinLY9nn86M7JOr5nmn5Yk6fJHy2X1WLRnE2Fwcd/1yNV1x/fTV1SY1usZgAAAAAAAADNi9Aapli5s0RzNxXJZrXo0hEdDnjeHSf31I9r8zRvc5EkyW616IyB7XX1mM7q2Ta+pcoFAAAAAAAA0EIIrWGKV2ZtkSSd2q+d2iVEHfC8Hm3j9Odju+i9Bdt11sAMTRjdSe0TD3w+AAAAAAAAgNaN0BotbkNeuT5fulOSNGFUx0Oef/vJPXX7yT2buSoAAAAAAAAAoYDQGi3CMAzN37JHL/28SdNW75ZhSIOyEzUou43ZpQEAAAAAAAAIIYTWaFZur19fLd+ll2dt1vKckuDxMd1T9fcz+phYGQAAAAAAAIBQRGiNZlNS6dE5z/6ijfkVkiSn3apzBmdqwqiO6pYeZ3J1AAAAAAAAAEIRoTWazZfLd2ljfoUSoyP0p9GddNHwDkqKcZhdFgAAAAAAAIAQRmiNZvPDmt2SpKuO6ayJx3U1uRoAAAAAAAAArYHV7AIQnqo9Ps3aUCBJOr5nmsnVAAAAAAAAAGgtCK3RLOZsLFS1x6/2CZHq2Zb51QAAAAAAAADqh9AazWJ6zWiQ43ulyWKxmFwNAAAAAAAAgNaC0BpNzjAM/bA6TxKjQQAAAAAAAAA0DKE1mtya3DLtLKlWZIRVI7ukmF0OAAAAAAAAgFaE0BpN7oc1gS7rUV1SFBlhM7kaAAAAAAAAAK0JoTWa3PTVv82zBgAAAAAAAICGILRGkyosd2nx9mJJzLMGAAAAAAAA0HCE1mhSP67Nl2FIvdvFq11ClNnlAAAAAAAAAGhlCK3RpH5YG5hnPZbRIAAAAAAAAAAagdAaTcbj8+untfmSGA0CAAAAAAAAoHEIrdFk5m8pUpnLq+QYhwZkJppdDgAAAAAAAIBWiNAaTeaH1YHRIL/rkSar1WJyNQAAAAAAAABaI0JrNJkf1jDPGgAAAAAAAMDhsZtdAMLDpvxybSqokN1q0THdUswuBwAAAKgXl9enJ6evV5XbrztP6SmHnb4eAAAAs7EiQ5Oo7bIe3jlJcZERJlcDAAAA1I/VYtEzMzbqlV82q8rtM7scAAAAiE5rNJBhGNpT6VGFy6sqj0+Vbp8q3V59sWyXJOn4nukmVwgAAADUX4TNKrvVIq/fUKXHqwTRgAEAAGC2kAqtH3roIU2ePFmTJk3SE088YXY52I9r31ykr1fkHvDxsT2ZZw0AAIDWJcphU1m1l05rAACAEBEyofX8+fP1/PPPq3///maXggPIK60OBtZOu1UxTruiImyKdgS+RndLUceUGJOrBAAAABomKiIQWlcSWgMAAISEkAity8vLNX78eL344ot64IEHzC4HB/D96sDc6gGZCfr0utEmVwMAAAA0jWiHTZJU7SG0BgAACAUhsRHjxIkTddppp2ncuHFml4KDmLYq0GV9Qm/mVgMAACDg559/1sUXX6wRI0YoJydHkvTf//5Xs2bNMrmy+ouMCITWdFoDAACEBtND63feeUeLFi3S1KlTD3muy+VSaWlpnS+0jAqXV79sLJQkndC7rcnVAAAAIBR8+OGHOumkkxQVFaXFixfL5XJJkkpKSvSPf/yjXtcIhTV+bad1FZ3WAAAAIcHU0Hr79u2aNGmS3nzzTUVGRh7y/KlTpyohISH4lZWV1QJVQpJ+Wpcvt9ev7KRodU+PNbscAAAAhIAHHnhAzz33nF588UVFREQEj48aNUqLFi2q1zVCYY0f7QhMTWQjRgAAgNBgami9cOFC5eXlafDgwbLb7bLb7Zo5c6aefPJJ2e12+Xx1F42TJ09WSUlJ8Gv79u0mVX7kmbZ6t6TAaBCLxWJyNQAAAAgFa9eu1ZgxY/Y5npCQoOLi4npdIxTW+IwHAQAACC2mbsQ4duxYLV++vM6xK664Qj179tQdd9whm81W5zGn0ymn09mSJUKS1+fXD2sCmzAyzxoAAAC12rZtqw0bNqhjx451js+aNUudO3eu1zVCYY3PeBAAAIDQctihdXV1db1Ge+xPXFyc+vbtW+dYTEyMkpOT9zkO8yzYukfFlR4lRkdoaIc2ZpcDAACAEHHVVVdp0qRJeuWVV2SxWLRz507NmTNHt956q6ZMmWJ2efUWVdNpXeX2mlwJAAAApEaG1n6/Xw8++KCee+457d69W+vWrVPnzp01ZcoUdezYUVdeeWVT1wkTTVsVGA1yfI802W2m790JAACAEHHnnXfK7/dr7Nixqqys1JgxY+R0OnXrrbfq+uuvN7u8eoui0xoAACCkNCqBfOCBB/Taa6/p4YcflsPhCB7v27evXnrppcMq6Mcff9QTTzxxWNdA0zEMIxhaMxoEAAAAe7NYLLrrrrtUVFSkFStWaO7cucrPz9f9999vdmkNUhtaM9MaAAAgNDQqtH799df1wgsvaPz48XXmTg8YMEBr1qxpsuJgvnW7y7WtqFIOu1VjuqeaXQ4AAABCkMPhUO/evTVs2DDFxsaaXU6DRdeMB6mm0xoAACAkNGo8SE5Ojrp27brPcb/fL4/Hc9hFIXR8vzrQZT2qS7JinKbu2wkAAIAQtGDBAr333nvatm2b3G53ncc++ugjk6pqGDqtAQAAQkujOq179+6tn3/+eZ/jH3zwgQYNGnTYRSF0fBccDdLW5EoAAAAQat555x2NHDlSq1ev1scffyyPx6OVK1fqhx9+UEJCgtnl1VtwpjWhNQAAQEhoVOvs3Xffrcsuu0w5OTny+/366KOPtHbtWr3++uv64osvmrpGmGR3abWWbi+WJI3tlWZuMQAAAAg5//jHP/T4449r4sSJiouL07///W916tRJ11xzjdq1a2d2efUWzUaMAAAAIaVRndZnnnmmPv/8c33//feKiYnR3XffrdWrV+vzzz/XCSec0NQ1wiS1o0EGZCUqPT7S5GoAAAAQajZu3KjTTjtNUmCudUVFhSwWi2666Sa98MILJldXf1ERjAcBAAAIJY0eUnzMMcdo2rRpTVkLQsy0mtEgJ/ZON7kSAAAAhKI2bdqorKxMkpSRkaEVK1aoX79+Ki4uVmVlpcnV1V+UI/DPIsaDAAAAhAZ21sN+lbu8mr2hUJJ0AqE1AAAA9mPMmDGaNm2a+vXrp/POO0+TJk3SDz/8oGnTpmns2LFml1dvtZ3WjAcBAAAIDY0KrX0+nx5//PED7hJeVFTUJMXBPD+vy5fb51eH5Gh1S4s1uxwAAACEoKefflrV1dWSpLvuuksRERGaPXu2zj33XP3tb38zubr6i2YjRgAAgJDSqND6vvvu00svvaRbbrlFf/vb33TXXXdpy5Yt+uSTT3T33Xc3dY1oYVsLK/TkDxskSSf0SpfFYjG5IgAAAISipKSk4M+tVqvuvPNOE6tpvMjgTGuvyZUAAABAamRo/eabb+rFF1/UaaedpnvvvVcXXnihunTpov79+2vu3Lm64YYbmrpOtADDMPTRohzd/ekKVbh9io+068Lh2WaXBQAAgBCXl5envLw8+f3+Osf79+9vUkUNU9tpXe3xH+JMAAAAtIRGhda5ubnq16+fJCk2NlYlJSWSpN///veaMmVK01WHFlNS5dHfPlmhz5fulCQN65ikxy8YqIzEKJMrAwAAQKhauHChLrvsMq1evVqGYdR5zGKxyOdrHeM2amdau31+eX1+2W1WkysCAAA4sjUqtM7MzNSuXbuUnZ2tLl266LvvvtPgwYM1f/58OZ3Opq4RzWz+liLd+M4S5RRXyWa16KZx3fSX33WVzcpYEAAAABzYhAkT1L17d7388stKT2+9Y+WiajqtpcBmjHGE1gAAAKZqVGh99tlna/r06Ro+fLiuv/56XXzxxXr55Ze1bds23XTTTU1dI5rRl8t26fq3F8lvSNlJ0XrigoEanN3G7LIAAADQCmzatEkffvihunbtanYph8Vpt8pqkfxGYDPGuMgIs0sCAAA4ojUqtH7ooYeCPz///POVnZ2tOXPmqFu3bjr99NObrDg0r8Jyl/72yXL5DemMAe314Nl9WaADAACg3saOHaulS5e2+tDaYrEoKsKmCrdPle7WMdIEAAAgnDUqtP5fI0aM0IgRI5riUmhB93+xSnsqPerVLl6P/nGAIvgYJAAAABrgpZde0mWXXaYVK1aob9++ioio2wBxxhlnmFRZw0U57Kpw+1TlIbQGAAAwW6ND6507d2rWrFn73SX8hhtuOOzC0LxmrsvXJ0t2ymqRHjqnH4E1AAAAGmzOnDn65Zdf9PXXX+/zWGvaiFGSohyB9TCd1gAAAOZrVGj92muv6ZprrpHD4VBycnKdDVcsFguhdYirdHt118fLJUmXj+ykAVmJ5hYEAACAVql2f5spU6YoPT3d7HIOS3RE4J9G1XRaAwAAmK5RofWUKVN09913a/LkybJa6dBtbR6ftk479lQpIzFKt5zY3exyAAAA0EoVFhbqpptuavWBtSRFOmyS6LQGAAAIBY1KnCsrK3XBBRcQWLdCy3eU6OVZmyVJD5zVVzHOJhlrDgAAgCPQOeecoxkzZphdRpOIjgiE1sy0BgAAMF+jEssrr7xS77//vu68886mrgfNyOvz686PlslvSKcPaK/jeqaZXRIAAABase7du2vy5MmaNWuW+vXrt89GjK1pbGBUTad1ldtrciUAAABoVGg9depU/f73v9c333yz38XpY4891iTFoWm98stmrdxZqoSoCN39+95mlwMAAIBW7qWXXlJsbKxmzpypmTNn1nmste1181toTac1AACA2RodWn/77bfq0aOHJO2zESNCz/aiSj02bZ0k6a5Teyk1zmlyRQAAAGjtNm/ebHYJTaZ2PEgl40EAAABM16jQ+tFHH9Urr7yiyy+/vInLQUN8vHiH9lR4dMWojod8s+DR79aq2uPX0Z2TdN7QzBaqEAAAAJDi4+O1ZMkSde7c2exSDohOawAAgNDRqNDa6XRq1KhRTV0LGiC/zKVb3lsqvyG1TYjUqf3aHfDcVTtL9enSnZKkv53Wm254AAAAtCjDMMwu4ZAIrQEAAEKHtTFPmjRpkp566qmmrgUN8O3KXPlr1v4PfLFKlQfZMOaRb9fIMKTf92+nvhkJLVQhAAAA0HpEMR4EAAAgZDSq0/rXX3/VDz/8oC+++EJ9+vTZZyPGjz76qEmKw4F9syI3+POdJdV6+ocNuv3knvucN29ToWaszZfdatGtJ/ZoyRIBAACAViO6ptO6mk5rAAAA0zUqtE5MTNQ555zT1LWgnvZUuDVnU6Ek6W+n9dIDX67Wiz9v0rlDMtUlNTZ4nmEY+uc3ayRJ5x+VpY4pMabUCwAAAIS6YKc1oTUAAIDpGhVav/rqq/U675dfftHQoUPldDob8zI4gGmrd8vnN9SrXbyuHN1Jv2wo0Iy1+br3s5V6fcKw4Mzq71fnadG2YkVGWDVpbDeTqwYAAMCRqjXsqRLlCPzTqIrxIAAAAKZr1Ezr+jrllFOUk5PTnC9xRKodDXJK37ayWCy65/Q+ctis+nl9gb5dGXjM5zf0yLeBLusJozopLT7StHoBAABwZGsVGzFGsBEjAABAqGjW0Lo1LE5bm9Jqj35eny8pEFpLUseUGF1zbGdJ0v1frFaV26ePF+do3e5yJURF6Jpju5hWLwAAAMLXjBkz6nXe119/rYyMjGau5vDUzrSm0xoAAMB8zRpao+n9sDpPHp+hLqkx6pYeFzx+7e+6KiMxSjnFVXps2lo9Pm2dJGnicV2UEBVxoMsBAAAAjXbyySerS5cueuCBB7R9+/YDnjd69OiQHxkY5aidae01uRIAAAAQWrcyX6/YJUk6tV+7OsejHDZN+X1vSdKLP29WTnGV2iVE6tIRHVu6RAAAABwhcnJydN111+mDDz5Q586dddJJJ+m9996T2+02u7QGqx0PUu3xm1wJAAAACK1bkQqXVz+uDYwGOblmNMjeTuqTrjHdU4O/vnFcN0XWLL4BAACAppaSkqKbbrpJS5Ys0bx589S9e3dde+21at++vW644QYtXbrU7BLrLZpOawAAgJDRrKF1a9glvDX5cW2+XF6/spOi1btd/D6PWywW3Xt6b8VF2tU3I17nDs40oUoAAAAciQYPHqzJkyfruuuuU3l5uV555RUNGTJExxxzjFauXGl2eYdU2+xRyUaMAAAApmMjxlakdjTIKX3bHvANgc6psfrlzuP1wZ9Hym6jkR4AAADNy+Px6IMPPtCpp56qDh066Ntvv9XTTz+t3bt3a8OGDerQoYPOO+88s8s8pNpOa5fXL7+ff8cAAACYyd6YJ91zzz2aMGGCOnTocNDzysrKGlUU9lXt8WnGmjxJ+x8Nsrf4SDZeBAAAQPO7/vrr9fbbb8swDF1yySV6+OGH1bdv3+DjMTEx+te//qX27dubWGX91G7EKElVHp9inI36pxIAAACaQKNacT/99FN16dJFY8eO1VtvvSWXy9XUdeF//Ly+QBVun9onRGpgVqLZ5QAAAABatWqVnnrqKe3cuVNPPPFEncC6VkpKimbMmGFCdQ0Taa8bWgMAAMA8jQqtlyxZovnz56tPnz6aNGmS2rZtq7/85S+aP39+U9d3RNleVKnHp63TipySfR6rHQ1y0kFGgwAAAAAtafr06brwwgvldDoPeI7dbtexxx7bglU1jtVqUWRE4J9HVcy1BgAAMFWjP/M2aNAgDRo0SI8++qg+//xzvfrqqxo1apR69uypK6+8UpdffrkSEhKastaw98CXq/Ttyt369/T1GtcrXZPGdlO/zAS5vX5NW7VbknRK33YmVwkAAAAEfPbZZ/s9brFYFBkZqa5du6pTp04tXFXjRTvsqva46bQGAAAw2WEPajMMQx6PR263W4ZhqE2bNnr66ac1ZcoUvfjiizr//PMP+Nxnn31Wzz77rLZs2SJJ6tOnj+6++26dcsoph1tWq+P1+TV7Y2Hw19+v3q3vV+/W8T3TNKxTksqqvUqJdWpIhzYmVgkAAAD85qyzzpLFYtlnA/baYxaLRaNHj9Ynn3yiNm1Cfx0bFREYEVJJpzUAAICpGjUeRJIWLlyo6667Tu3atdNNN92kQYMGafXq1Zo5c6bWr1+vBx98UDfccMNBr5GZmamHHnpICxcu1IIFC3T88cfrzDPP1MqVKxtbVqu1Ymepyqq9iou067ubxujsQRmyWqQf1uTpoa/XSJJO7psum5XRIAAAAAgN06ZN01FHHaVp06appKREJSUlmjZtmoYPH64vvvhCP/30kwoLC3XrrbeaXWq91G7GyHgQAAAAczWq07pfv35as2aNTjzxRL388ss6/fTTZbPZ6pxz4YUXatKkSQe9zumnn17n1w8++KCeffZZzZ07V3369GlMaa3WLxsKJElHd05W9/Q4PX7+QN0wtpuembFBHy/Okc9v6KyBGSZXCQAAAPxm0qRJeuGFFzRy5MjgsbFjxyoyMlJXX321Vq5cqSeeeEITJkwwscr6i64NrT1ekysBAAA4sjUqtP7jH/+oCRMmKCPjwCFqSkqK/H5/va/p8/n0/vvvq6KiQiNGjNjvOS6XSy6XK/jr0tLS+hcd4ubUjAYZ1SU5eKxTSoz+dd4ATRrbTXsq3eqfmWhSdQAAAMC+Nm7cqPj4+H2Ox8fHa9OmTZKkbt26qaCg4IDXCKU1fiTjQQAAAEJCo8aDTJky5aCBdUMsX75csbGxcjqd+vOf/6yPP/5YvXv33u+5U6dOVUJCQvArKyurSWowW7XHp/lbiiRJo7qm7PN4VlI0gTUAAABCzpAhQ3TbbbcpPz8/eCw/P1+33367jjrqKEnS+vXrD7puD6U1fjTjQQAAAEJCozqtb7755v0e33uX8DPPPFNJSUmHvFaPHj20ZMkSlZSU6IMPPtBll12mmTNn7je4njx5cp3XLi0tDYvgetG2PXJ5/UqNc6prWqzZ5QAAAAD18tJLL+mss85SZmZmcF2+fft2de7cWZ9++qkkqby8XH/7298OeI1QWuPXbsRY5SG0BgAAMFOjQuvFixdr0aJF8vl86tGjhyRp3bp1stls6tmzp/7v//5Pt9xyi2bNmnXArulaDodDXbt2lRTo1Jg/f77+/e9/6/nnn9/nXKfTKafT2ZiSQ1rtaJCRXZJlsbDRIgAAAFqHnj17atWqVfruu++0bt06SYGmlBNOOEFWa+BDnWedddZBrxFKa3w2YgQAAAgNjQqta7uoX3311eAMu5KSEv3pT3/S6NGjddVVV+miiy7STTfdpG+//bZB1/b7/XVm2h0JajdhHNVl39EgAAAAQCjyeDyKiorSkiVLdPLJJ+vkk082u6TDFsVMawAAgJDQqND6kUce0bRp0+psupKQkKB7771XJ554oiZNmqS7775bJ5544kGvM3nyZJ1yyinKzs5WWVmZ3nrrLf34448NDrpbs7Jqj5buKJEkjeyafIizAQAAgNAQERGh7Oxs+XzhE/DWzrSuZjwIAACAqRq1EWNJSYny8vL2OZ6fnx/c7TsxMVFut/ug18nLy9Oll16qHj16aOzYsZo/f76+/fZbnXDCCY0pq1X6dXORfH5D2UnRymwTbXY5AAAAQL3ddddd+utf/6qioiKzS2kSdFoDAACEhkaPB5kwYYIeffTR4K7g8+fP16233hqcWffrr7+qe/fuB73Oyy+/3JiXDyuza+ZZj6LLGgAAAK3M008/rQ0bNqh9+/bq0KGDYmJi6jy+aNEikyprnChH4J9HbMQIAABgrkaF1s8//7xuuukmXXDBBfJ6vYEL2e267LLL9Pjjj0sKbMry0ksvNV2lYap2nvVI5lkDAACglTnUJoutTTQbMQIAAISEBofWPp9PixYt0sMPP6zHH39cmzZtkiR17txZsbGxwfMGDhzYZEWGq4Jyl9bklkmSRnah0xoAAACtyz333GN2CU3qt/EgXpMrAQAAOLI1eKa1zWbTiSeeqOLiYsXGxqp///7q379/ncAa9TN3U2A0SM+2cUqOdZpcDQAAANBwxcXFeumllzR58uTgbOtFixYpJyfH5MoaLqq205rxIAAAAKZq1HiQvn37atOmTerUqVNT13NE+WVDILRmNAgAAABao2XLlmncuHFKSEjQli1bdNVVVykpKUkfffSRtm3bptdff93sEhukttOa8SAAAADmanCntSQ98MADuvXWW/XFF19o165dKi0trfOF+pm9MTDPmk0YAQAA0BrdfPPNuvzyy7V+/XpFRkYGj5966qn66aefTKyscaLptAYAAAgJjeq0PvXUUyVJZ5xxhiwWS/C4YRiyWCzy+VjkHcqOPZXaWlgpm9WiYZ2SzC4HAAAAaLD58+fr+eef3+d4RkaGcnNzTajo8EQ6amda8+8ZAAAAMzUqtJ4xY0ZT13HEmb0xMBpkQGaC4iIjTK4GAAAAaDin07nfT1quW7dOqampJlR0eGo7ravptAYAADBVo0LrY489tqnrOOLM3hAYDcI8awAAALRWZ5xxhv7+97/rvffekyRZLBZt27ZNd9xxh84991yTq2u42pnWdFoDAACYq1EzrSXp559/1sUXX6yRI0cGdwb/73//q1mzZjVZceHKMAz9UtNpPZJ51gAAAGilHn30UZWXlystLU1VVVU69thj1bVrV8XFxenBBx80u7wGi9prprVhGCZXAwAAcORqVKf1hx9+qEsuuUTjx4/XokWL5HK5JEklJSX6xz/+oa+++qpJiww3G/PLlV/mktNu1eDsNmaXAwAAADRKQkKCpk2bplmzZmnZsmUqLy/X4MGDNW7cOLNLa5RoR+CfR4Yhubx+RdZ0XgMAAKBlNSq0fuCBB/Tcc8/p0ksv1TvvvBM8PmrUKD3wwANNVly4+nFtviTpqI5JLIQBAADQ6o0ePVqjR482u4zDFrXX2rzS7WOtDgAAYJJGhdZr167VmDFj9jmekJCg4uLiw60prBmGoQ8W7pAkjeuVZnI1AAAAwOGZPn26pk+frry8PPn9/jqPvfLKKyZV1Tg2q0UOu1Vur19VbMYIAABgmkbNtG7btq02bNiwz/FZs2apc+fOh11UOFu6o0RrcsvksFt19qBMs8sBAAAAGu2+++7TiSeeqOnTp6ugoEB79uyp89Ua1XZbV7m9JlcCAABw5GpUp/VVV12lSZMm6ZVXXpHFYtHOnTs1Z84c3XrrrZoyZUpT1xhW3p2/TZJ0at+2SoiOMLkaAAAAoPGee+45vfbaa7rkkkvMLqXJRDtsKqnyqMrtP/TJAAAAaBaNCq3vvPNO+f1+jR07VpWVlRozZoycTqduvfVWXX/99U1dY9iocHn12ZKdkqQLhmWbXA0AAABweNxut0aOHGl2GU2qttO6kk5rAAAA0zRqPIjFYtFdd92loqIirVixQnPnzlV+fr7uv//+pq4vrHyxbKcq3D51SonR8E5JZpcDAAAAHJY//elPeuutt8wuo0lFOWrGgzDTGgAAwDSN6rSu5XA41Lt376aqJey9M3+7JOn8o7JksVhMrgYAAAA4PNXV1XrhhRf0/fffq3///oqIqDv+7rHHHjOpssb7baY1oTUAAIBZGhVaV1RU6KGHHjrgLuGbNm1qkuLCydrcMi3eViy71aJzBmeYXQ4AAABw2JYtW6aBAwdKklasWFHnsdbapEGnNQAAgPkaFVr/6U9/0syZM3XJJZeoXbt2rXZB2pLeqdmAcWyvNKXFRZpcDQAAAHD4ZsyYYXYJTS7aUTvTmtAaAADALI0Krb/++mt9+eWXGjVqVFPXE5aqPT59vDhHEhswAgAAIPxs2LBBGzdu1JgxYxQVFSXDMFptYwvjQQAAAMzXqI0Y27Rpo6QkNhKsr+9W7VZxpUftEyI1pluq2eUAAAAATaKwsFBjx45V9+7ddeqpp2rXrl2SpCuvvFK33HKLydU1TpQj0NfDeBAAAADzNCq0vv/++3X33XersrKyqesJS+/8GhgNct7QLNmsrbPjBAAAAPhfN910kyIiIrRt2zZFR0cHj59//vn65ptvTKys8Wo7rRkPAgAAYJ5GjQd59NFHtXHjRqWnp6tjx4777BK+aNGiJikuHGwtrNDsjYWyWKTzhmaaXQ4AAADQZL777jt9++23ysysu87t1q2btm7dalJVh6d2pnU1ndYAAACmaVRofdZZZzVxGa2DYRhanlOignKXRnVNkdNuO+Rz3luwXZJ0TLdUZbaJPsTZAAAAQOtRUVFRp8O6VlFRkZxOpwkVHb6o4EaMXpMrAQAAOHI1KrS+5557mrqOVuOPz89Rtcevn247TtnJBw+hvT6/3l+wQ5J04VFZLVEeAAAA0GKOOeYYvf7667r//vslSRaLRX6/Xw8//LCOO+44k6trnOBGjB6/yZUAAAAcuRoVWktScXGxPvjgA23cuFG33XabkpKStGjRIqWnpysjI6MpawwZFotFKbFO7dhTpfxy1yFD6/lb9iivzKWkGIfG9kpvoSoBAACAlvHwww9r7NixWrBggdxut26//XatXLlSRUVF+uWXX8wur1FqO62r6LQGAAAwTaNC62XLlmncuHFKSEjQli1bdNVVVykpKUkfffSRtm3bptdff72p6wwZwdC6zHXIc3cWV0mS+rSPl8PeqD0vAQAAgJDVt29frVu3Tk8//bTi4uJUXl6uc845RxMnTlS7du3MLq9RamdaVzHTGgAAwDSNCq1vvvlmXX755Xr44YcVFxcXPH7qqafqoosuarLiQlFqXGA2X0H5oUPr/JpzUmJb5zw/AAAA4FASEhJ01113HfSca6+9Vn//+9+VkpLSQlU1Xu14kEo3oTUAAIBZGtX+O3/+fF1zzTX7HM/IyFBubu5hFxXKagPo+oTWBTXd2LVBNwAAAHAkeuONN1RaWmp2GfXy23gQQmsAAACzNCq0djqd+110rlu3TqmpqYddVChLjXVIqmdoHey0djRrTQAAAEAoMwzD7BLqjfEgAAAA5mtUaH3GGWfo73//uzwej6TABoXbtm3THXfcoXPPPbdJCww1KbXjQcrchzyX8SAAAABA6xLJeBAAAADTNSq0fvTRR1VeXq60tDRVVVXp2GOPVdeuXRUXF6cHH3ywqWsMKQ0bDxIIthkPAgAAALQO0Y7Atj/VhNYAAACmadRGjAkJCZo2bZp++eUXLV26VOXl5Ro8eLDGjRvX1PWFnIaE1nRaAwAAAK1LcCNGj0+GYchisZhcEQAAwJGnUaF1rVGjRmnUqFEHfLxfv3766quvlJWVdTgvE1Jq51Pnlx08tPb4/NpTSac1AAAA0JrUbsTo8xvy+Aw57ITWAAAALa1R40Hqa8uWLcG51+GidqZ1hdt30B3FiyrcMgzJapHaRLMRIwAAAI5cF198seLj480uo15qO60lHXS9DwAAgOZzWJ3WR6I4p11Ou1Uur18F5S5lJUXv97zaTuzkWKdsVrozAAAAEJ6Ki4v166+/Ki8vT36/v85jl156qSTp2WefNaO0RnHYrbJbLfL6DVV5fEpQhNklAQAAHHEIrRvIYrEoJdapnOIq5R8ktC5gnjUAAADC3Oeff67x48ervLxc8fHxdeY/WyyWYGjd2kQ5bCqr9qrS7TW7FAAAgCNSs44HCVe1I0IKDjLXurbTunYGNgAAABBubrnlFk2YMEHl5eUqLi7Wnj17gl9FRUVml9dotSNCqjyMBwEAADADoXUjpNYE0QXl7gOeU/sYmzACAAAgXOXk5OiGG25QdPT+P33YWkXXbMbITGsAAABzmBpaT506VUcddZTi4uKUlpams846S2vXrjWzpHqpHflROwJkf2o7rVMZDwIAAIAwddJJJ2nBggVml9HkIms6rSsJrQEAAEzRrDOtn3/+eaWnpx/w8ZkzZ2rixIk66qij5PV69de//lUnnniiVq1apZiYmOYs7bDUJ7SufYxOawAAAISr0047TbfddptWrVqlfv36KSKi7qaFZ5xxhkmVHZ5gpzXjQQAAAExR79D6ySefrPdFb7jhBknSRRdddNDzvvnmmzq/fu2115SWlqaFCxdqzJgx9X69llY7pzq/XjOtCa0BAAAQnq666ipJ0t///vd9HrNYLPL5WmfoG8V4EAAAAFPVO7R+/PHH63WexWIJhtYNVVJSIklKSkra7+Mul0su129BcWlpaaNe53AFN2Kk0xoAAABHML/ff9jXCJU1/t6iIgL/TKLTGgAAwBz1Dq03b97cnHXI7/frxhtv1KhRo9S3b9/9njN16lTdd999zVpHfaQGx4McbCNGOq0BAACAQwmVNf7eajutmWkNAABgjmadad0QEydO1IoVKzRr1qwDnjN58mTdfPPNwV+XlpYqKyurJcqrI9hpfYDxIB6fX3sqPYFza0aJAAAAAOHgySef1NVXX63IyMhDjhCszycwQ2WNv7fomo0Yq+m0BgAAMEWjQ+sdO3bos88+07Zt2+R21+04fuyxxxp0reuuu05ffPGFfvrpJ2VmZh7wPKfTKafT/M7l2u7pMpdX1R5fcHfxWoU1Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAA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3W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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BgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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w5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import csv\n", "import matplotlib.pyplot as plt\n", @@ -294,9 +428,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mUsage: \u001b[0mapax [OPTIONS] COMMAND [ARGS]...\n", + "\u001b[2mTry \u001b[0m\u001b[2;34m'apax \u001b[0m\u001b[1;2;34m-h\u001b[0m\u001b[2;34m'\u001b[0m\u001b[2m for help.\u001b[0m\n", + "\u001b[31m╭─\u001b[0m\u001b[31m Error \u001b[0m\u001b[31m─────────────────────────────────────────────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", + "\u001b[31m│\u001b[0m No such command 'evaluate'. \u001b[31m│\u001b[0m\n", + "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + } + ], "source": [ "!apax evaluate config_minimal.yaml" ] @@ -334,19 +488,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "!rm -r project config.yaml error_config.yaml" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From c361f0eb4e99d653e91503f425f529a8e960f0dc Mon Sep 17 00:00:00 2001 From: Nico Segreto Date: Fri, 1 Mar 2024 22:07:48 +0100 Subject: [PATCH 075/192] Experiment 01 update (#236) * mod_config bug fix * Model training example --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- apax/utils/__init__.pyi | 2 +- apax/utils/helpers.py | 5 +- examples/01_Model_Training.ipynb | 350 +++++++++++++++++++++++++++---- tests/conftest.py | 2 +- 4 files changed, 313 insertions(+), 46 deletions(-) diff --git a/apax/utils/__init__.pyi b/apax/utils/__init__.pyi index 289ae4ae..c87a369c 100644 --- a/apax/utils/__init__.pyi +++ b/apax/utils/__init__.pyi @@ -1,3 +1,3 @@ -from . import convert, data, jax_md_reduced, math, random, datasets +from . import convert, data, datasets, jax_md_reduced, math, random __all__ = ["convert", "data", "math", "random", "jax_md_reduced", datasets] diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 398ff899..35c96d33 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -17,5 +17,8 @@ def mod_config(config_path, updated_config): config_dict = yaml.safe_load(stream) for key, new_value in updated_config.items(): - config_dict[key].update(new_value) + if isinstance(config_dict[key], dict): + config_dict[key].update(new_value) + else: + config_dict[key] = new_value return config_dict diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index b91df92f..46f0c786 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -26,8 +26,7 @@ "data_path = Path(\"project\")\n", "\n", "file_path = download_md17_benzene_DFT(data_path)\n", - "file_path = mod_md17(file_path)\n", - "\n" + "file_path = mod_md17(file_path)" ] }, { @@ -92,23 +91,45 @@ "!apax -h" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following command create a minimal configuration file in the working directory." + ] + }, { "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "There is already a config file in the working directory.\n" - ] - } - ], + "outputs": [], "source": [ "!apax template train" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", + "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Further, the units of the labels have to be specified. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", + "\n", + "The filled in configuration file should look similar to this one.\n", + "\n", + "```yaml\n", + "epoch: 1000\n", + "data:\n", + " data_path: md17.extexyz\n", + " epochs: 1000\n", + " n_train: 1000\n", + " energy_unit: kcal/mol\n", + " pos_unit: Ang\n", + " ....\n", + "```\n", + "\n", + "It also can be modefied with the utils function `mod_config` provided by Apax.\n" + ] + }, { "cell_type": "code", "execution_count": 4, @@ -116,47 +137,95 @@ "outputs": [], "source": [ "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", "\n", "config_path = Path(\"config.yaml\")\n", "\n", "config_updates = {\n", + " \"n_epochs\": 10,\n", " \"data\": {\n", + " \"experiment\": \"benzene_dft_cli\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(file_path),\n", " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", " }\n", "}\n", - "config_dict = mod_config(config_path, config_updates)" + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", - "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", "\n", - "The filled in configuration file should look similar to this one.\n", - "\n", - "```yaml\n", - "data:\n", - " data_path: md17.extexyz\n", - " epochs: 1000\n", - " n_train: 1000\n", - " ....\n", - "```" + "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "config.yaml is a valid training config.\n" + ] + } + ], + "source": [ + "!apax validate train config.yaml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n", - "\n", - "`apax validate train config_minimal.yaml`\n", - "\n", "Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file.\n", - "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:\n", + "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "config_updates = {\n", + " \"n_epochs\": -1000,\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", "\n", - "`PYDANTIC ERROR`" + "with open(\"error_config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 validation error for Config\n", + "n_epochs\n", + " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", + " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", + "\u001b[31mConfiguration Invalid!\u001b[0m\n" + ] + } + ], + "source": [ + "!apax validate train error_config.yaml" ] }, { @@ -165,9 +234,46 @@ "source": [ "## Training\n", "\n", - "Model training can be started by running\n", + "Model training can be started by running" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 21:56:40 | Initializing Callbacks\n", + "INFO | 21:56:40 | Initializing Loss Function\n", + "INFO | 21:56:40 | Initializing Metrics\n", + "INFO | 21:56:40 | Running Input Pipeline\n", + "INFO | 21:56:40 | Read data file project/benzene_mod.xyz\n", + "INFO | 21:56:40 | Loading data from project/benzene_mod.xyz\n", + "INFO | 21:56:50 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13135.40it/s]\n", + "INFO | 21:56:50 | Computing per element energy regression.\n", + "INFO | 21:56:57 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12868.33it/s]\n", + "INFO | 21:56:57 | Initializing Model\n", + "INFO | 21:56:58 | initializing 1 models\n", + "INFO | 21:57:04 | Initializing Optimizer\n", + "INFO | 21:57:04 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" + ] + } + ], + "source": [ + "!apax train config.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "`apax train config.yaml`\n", "\n", "During training, apax displays a progress bar to keep track of the validation loss.\n", "This progress bar is optional however and can be turned off in the config. LINK\n", @@ -179,38 +285,180 @@ " - CSV\n", "```\n", "\n", - "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint." + "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint.\n", + "\n", + "Furthermore, an Apax trianing can easily be started within a scriped." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 9, "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 10410.16it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11413.38it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:43<00:00, 2.24s/it, val_loss=0.31]\n" + ] + } + ], "source": [ - "TODO plot train val loss" + "from apax.train.run import run\n", + "\n", + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"experiment\": \"benzene_dft_script\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " }\n", + "}\n", + "\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "run(config_dict)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWD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Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAAWItieIxIS6IzHAAAAJCksWPH6vPPP7c6jKhzBmeG+3wWRwIAANA+tejM8D/96U/KzMxsybuIG4xJAQAAAALOPfdc3XXXXVq7dq2GDBkip9MZdv35559vUWRHxk1nOAAAgKWaXQx/+umnm33QW265RZJ0+eWXH35E7VSwGF5KMRwAAADt3LXXXitJeuihhxpdZxiGfG20s9plpxgOAABgpWYXw5988slm7WcYRqgYjuajMxwAAAAI8Pvjs1gcnBnu9ZkWRwIAANA+NbsYXlBQ0JJxtHvBYnhxJcVwAAAAIB4Fi+E1dIYDAABYokVnhqP5WEATAAAA7dnTTz+t6667TgkJCT86orGtfhI1NCbFRzEcAADAChEXw7dv365//etf2rp1qzweT9h1M2bMOOLA2puU4Mzwaq/8flM2m2FxRAAAAEDrefLJJzV+/HglJCT84IjGtjyW0RlaQLNtzjwHAABo6yIqhi9dulTnn3+++vTpo3Xr1umYY47Rli1bZJqmjj322GjH2C4Ex6SYplRWUxv6GQAAAGgPGo5ljNcRjSygCQAAYC1bJDeaPHmy7rzzTq1Zs0YJCQl67bXXtG3bNp166qm66KKLoh1ju+B22JXgDJyOUkalAAAAAHHH7WBMCgAAgJUi6gz/9ttvNX/+/MABHA5VVVWpY8eOeuihh3TBBRfo+uuvj2qQ7UVqolPV3hoVV3qVk251NAAAAIB14nEsY3ABTW+taXEkAAAA7VNExfAOHTqEEtJu3bpp8+bNGjx4sCRp79690YuunUlLdKmotIZFNAEAANCuxetYRhed4QAAAJaKaEzKCSecoI8++kiSdM455+iOO+7Q7373O1199dU64YQTohpgexKcE04xHAAAAO1ZvI5lZGY4AACAtSLqDJ8xY4bKy8slSQ8++KDKy8u1cOFC9e/fv81+ZDEWpFAMBwAAAOJ2LKOzrhheQzEcAADAEhEVwx999FFdccUVkgIjU2bPnh3VoNorOsMBAACA+B3LGBqTUuuzOBIAAID2KaIxKXv27NHZZ5+tnJwc3XXXXVq9enW042qXgsXw4irPj+wJAAAAxK94HcvoZmY4AACApSIqhr/++uvatWuXpkyZos8++0zHHnusBg8erEcffVRbtmyJcojtR1pSoBheSmc4AAAA2rEZM2Zo9OjRkgJjGc844wwtXLhQvXr10osvvmhxdJGr7wynGA4AAGCFiMakSFKnTp103XXX6brrrtP27ds1f/58zZkzR1OnTlVtbW00Y2w3GJMCAACA9s7n82n79u0aOnSopPgayxhcQNNvSj6/KbvNsDgiAACA9iWizvCGvF6vPv/8c61cuVJbtmxRZmZmNOJqlyiGAwAAoL2z2+0666yzdODAAatDibpgZ7hEdzgAAIAVIi6Gf/DBB7r22muVmZmpq666SikpKXrjjTe0ffv2aMbXrlAMBwAAAKRjjjlG3333ndVhRJ3TTjEcAADAShGNSenevbv279+vs88+W3/+85913nnnye12Rzu2dicluIBmJcVwAAAAtF+PPPKI7rzzTj388MMaOXKkOnToEHZ9SkqKRZEdGae9fixKjc8nyWldMAAAAO1QRMXwBx54QBdddJHS0tKiHE77FlxAk85wAAAAtGfnnHOOJOn888+XYdQXkE3TlGEY8vl8VoV2RAzDkMthk6fWT2c4AACABSIak3LttddGtRA+a9Ys9erVSwkJCRo9erQ+/fTTQ+47d+5cGYYRdklISAjbxzRNTZ06Vd26dVNiYqJyc3O1cePGqMXbUoJjUsqqa+XzmxZHAwAAAFjjL3/5i9577z198MEHev/990OXpUuXas6cOVaHd0TcdaNSKIYDAAC0vog6w6Np4cKFysvL0+zZszV69GjNnDlTY8eO1fr169W1a9cmb5OSkqL169eHfm7YLSJJjz/+uJ5++mnNmzdPvXv31pQpUzR27FitXbu2UeE8lgSL4ZJUVu1VWpLLwmgAAAAAa1x99dXatWtXo9cD+/btU25uriZOnGhRZEfO5bBJNZLXR/MLAABAa4t4Ac1omTFjhq699lpNmjRJgwYN0uzZs5WUlPSDHR+GYSgrKyt0yczMDF1nmqZmzpyp3/72t7rgggs0dOhQvfTSS9q5c6cWLVrUCo8ock67TUkuuyRGpQAAAKD9Co5DOVh5eXlMN7c0h8tBZzgAAIBVLO0M93g8WrVqlSZPnhzaZrPZlJubqxUrVhzyduXl5erZs6f8fr+OPfZYPfrooxo8eLAkqaCgQIWFhcrNzQ3tn5qaqtGjR2vFihW69NJLGx2vpqZGNTU1oZ9LS0uj8fAikproVKXHp+JKr3p2tiwMAAAAoNXl5eVJCjS/TJkyRUlJSaHrfD6fVq5cqeHDhzfrWLGU4zfkDI5JaaNzzwEAANoyS4vhe/fulc/nC+vslqTMzEytW7euydsMGDBAc+bM0dChQ1VSUqI//OEPOvHEE/XNN9/oqKOOUmFhYegYBx8zeN3Bpk2bpgcffDAKj+jIpSY6taukms5wAAAAtDtffvmlpEBn+Jo1a+Ry1Y8NdLlcGjZsmO68885mHSuWcvyGgp3hNXSGAwAAtDrLZ4YfrjFjxmjMmDGhn0888UQdffTR+tOf/qSHH344omNOnjw51IUiBbpGcnJyjjjWSATnhlMMBwAAQHvzwQcfSJImTZqkp556SikpKREfK5Zy/IZcLKAJAABgGUuL4RkZGbLb7SoqKgrbXlRUpKysrGYdw+l0asSIEdq0aZMkhW5XVFSkbt26hR3zUB+pdLvdcrvdETyC6KMYDgAAgPbuL3/5yxEfI5Zy/IaYGQ4AAGAdSxfQdLlcGjlypJYuXRra5vf7tXTp0rDu7x/i8/m0Zs2aUOG7d+/eysrKCjtmaWmpVq5c2exjWoliOAAAABC/gsVwr8+0OBIAAID2x/IxKXl5eZo4caJGjRql448/XjNnzlRFRYUmTZokSZowYYK6d++uadOmSZIeeughnXDCCerXr5+Ki4v1+9//Xt9//72uueYaSYHFdm677TY98sgj6t+/v3r37q0pU6YoOztbF154oVUPs9kohgMAAADxy+1gAU0AAACrWF4Mv+SSS7Rnzx5NnTpVhYWFGj58uBYvXhxaAHPr1q2y2eob2A8cOKBrr71WhYWF6tSpk0aOHKmPP/5YgwYNCu1z9913q6KiQtddd52Ki4t18skna/HixUpISGj1x3e40pLqiuGVFMMBAACAeMPMcAAAAOsYpmny+byDlJaWKjU1VSUlJUe0aE8k/rpii6a8/o3OHpyl2VeObNX7BgAAiHdW5nmwVqyc+1//dZUWf1Oohy8YrCvH9LIsDgAAgHhxOHmepTPD0VgKY1IAAACAuBWcGV5DZzgAAECroxgeY5gZDgAAAMQvV2hmOMVwAACA1kYxPMZQDAcAAADiV7AY7q1lWiUAAEBroxgeY9KSXJIohgMAAADxKLSAps9ncSQAAADtD8XwGBPsDC+vqVUtH50EAAAA4oo7OCaFmeEAAACtjmJ4jElJcIS+L62utTASAAAAANHmtFMMBwAAsArF8BjjsNvU0R0oiDMqBQAAAIgvLKAJAABgHYrhMSg4KqW40mNxJAAAAACiKVgMr6EzHAAAoNVRDI9BwWI4neEAAABAfHExJgUAAMAyFMNjEMVwAAAAID4FO8O9jEkBAABodRTDY1CwGF5KMRwAAACIK6GZ4XSGAwAAtDqK4TGIznAAAAAgPoXGpNAZDgAA0Ooohseg1KTgApoUwwEAAIB4kuAMvASr9PgsjgQAAKD9oRgeg+gMBwAAAOJTdlqiJGnb/iqLIwEAAGh/KIbHIIrhAAAAQHzqldFBkrS3vEblNbUWRwMAANC+UAyPQRTDAQAAgPiUkuBU5w4uSdKWvRUWRwMAANC+UAyPQRTDAQAAgPjVs3OSJGnLPorhAAAArYlieAyiGA4AAADEr+CoFDrDAQAAWhfF8BiUlkQxHAAAAIhXvTvXFcP3VVocCQAAQPtCMTwGBTvDKz0+eX1+i6MBAAAAEE10hgMAAFiDYngMSk5whr6nOxwAAACIL71CneEUwwEAAFoTxfAYZLcZSk5wSKIYDgAAAMSbXhmBBTT3lntUVk2+DwAA0Foohseo4KiU4kqSYwAAACCeJCc4ldHRJUnaspe54QAAAK2FYniMCi6iWUpnOAAAABB3GJUCAADQ+iiGx6hgZzhjUgAAAID4wyKaAAAArY9ieIyiGA4AAADEr16dA3PDC+gMBwAAaDUUw2MUxXAAAAAgftEZDgAA0PoohseoFBbQBAAAAOJWcGb49/tYQBMAAKC1UAyPUXSGAwAAAPEr2Bm+r8Kj0mpyfgAAgNZAMTxGpSW6JFEMBwAAAOJRR7dDXZLdkhiVAgAA0Fpiohg+a9Ys9erVSwkJCRo9erQ+/fTTQ+77/PPP65RTTlGnTp3UqVMn5ebmNtr/qquukmEYYZezzz67pR9GVAU7w0sphgMAAABxKbSIJsVwAACAVmF5MXzhwoXKy8vT/fffry+++ELDhg3T2LFjtXv37ib3X7ZsmS677DJ98MEHWrFihXJycnTWWWdpx44dYfudffbZ2rVrV+gyf/781ng4UcOYFAAAACC+BeeGb9nL3HAAAIDWYHkxfMaMGbr22ms1adIkDRo0SLNnz1ZSUpLmzJnT5P5///vfdcMNN2j48OEaOHCgXnjhBfn9fi1dujRsP7fbraysrNClU6dOrfFwoiZYDC+u8lgcCQAAAICWEJwb/v0+OsMBAABag6XFcI/Ho1WrVik3Nze0zWazKTc3VytWrGjWMSorK+X1epWenh62fdmyZeratasGDBig66+/Xvv27TvkMWpqalRaWhp2sRqd4QAAAEDkYjHHP1jvumJ4AcVwAACAVmFpMXzv3r3y+XzKzMwM256ZmanCwsJmHeM3v/mNsrOzwwrqZ599tl566SUtXbpU06dP1/LlyzVu3Dj5fL4mjzFt2jSlpqaGLjk5OZE/qChJTQoUw6u9ftXUNh03AAAAgKbFYo5/sJ51M8NZQBMAAKB1WD4m5Ug89thjWrBggf75z38qISEhtP3SSy/V+eefryFDhujCCy/UG2+8oc8++0zLli1r8jiTJ09WSUlJ6LJt27ZWegSHlux2yDAC39MdDgAAAByeWMzxDxacGX6g0quSSnJ+AACAlmZpMTwjI0N2u11FRUVh24uKipSVlfWDt/3DH/6gxx57TO+++66GDh36g/v26dNHGRkZ2rRpU5PXu91upaSkhF2sZrMZSkkIdIeXUgwHAAAADkss5vgH6+B2qGuyW5K0hVEpAAAALc7SYrjL5dLIkSPDFr8MLoY5ZsyYQ97u8ccf18MPP6zFixdr1KhRP3o/27dv1759+9StW7eoxN1aQoto0iUCAAAAxKXgIpoUwwEAAFqe5WNS8vLy9Pzzz2vevHn69ttvdf3116uiokKTJk2SJE2YMEGTJ08O7T99+nRNmTJFc+bMUa9evVRYWKjCwkKVl5dLksrLy3XXXXfpk08+0ZYtW7R06VJdcMEF6tevn8aOHWvJY4wUi2gCAAAA8a133aiUAuaGAwAAtDiH1QFccskl2rNnj6ZOnarCwkINHz5cixcvDi2quXXrVtls9TX75557Th6PR7/85S/DjnP//ffrgQcekN1u11dffaV58+apuLhY2dnZOuuss/Twww/L7Xa36mM7UmlJFMMBAACAeNYzg0U0AQAAWovlxXBJuummm3TTTTc1ed3Bi15u2bLlB4+VmJiod955J0qRWSuFznAAAAAgroU6w/dVWhwJAABA/LN8TAoOjTEpAAAAQHwLzgz/npnhAAAALY5ieAxjAU0AAAAgvvWq6wwvrvSquNJjcTQAAADxjWJ4DAsWw0vpDAcAAADiUqLLrqyUBEksogkAANDSKIbHsDTGpAAAAABxr2fnukU0GZUCAADQoiiGxzBmhgMAAADxr3fd3PAte1lEEwAAoCVRDI9hwWJ4UVm1TNO0OBoAAAAALSG4iCad4QAAAC2LYngMG5SdIrfDpm37q/RpwX6rwwEAAADQAoKLaG5hZjgAAECLohgew9KSXPrFyKMkSS98VGBxNAAAAABaQnBMSsHeCj4RCgAA0IIohse4q0/qLUl679siOkUAAACAONQjPbCAZml1rQ5Usl4QAABAS6EYHuP6de2o0wd0kWlKf/kv3eEAAABAvEl02dUtNUESc8MBAABaEsXwNuBXJ/eRJL26artK6BQBAAAA4g5zwwEAAFoexfA24KR+nTUwK1mVHp/mf7bV6nAAAAAARFmvurnhm3aXWxwJAABA/KIY3gYYhqGrTw7MDp/38RZ5fX6LIwIAAAAQTSN6pEmS/vrJ9yoqrbY2GAAAgDhFMbyNOH9YtjI6urSrpFpvf11odTgAAAAAoujnI7pr6FGpKquu1W8XfS3TNK0OCQAAIO5QDG8jEpx2XXlCL0nSi//5juQYAAAAiCMOu02P/3KonHZDS9YW6Y2vdlkdEgAAQNyhGN6GjD+hh1wOm1ZvL9Gq7w9YHQ4AAACAKBqYlaIbTusnSXrgX99of4XH4ogAAADiC8XwNiSjo1s/H9FdkvTCfwosjgYAAABAtN14ej8NyEzWvgqPHvz3N1aHAwAAEFcohrcxwYU0311bqG37Ky2OBgAAAEA0uRyBcSk2Q3o9f6eWfltkdUgAAABxg2J4G/OTzGSd0j9DfjPw0ckqj8/qkAAAAABE0bCcNF1zSh9J0n3//Fql1V6LIwIAAIgPFMPboFvO6C+HzdDSdbt10Z8+1s7iKqtDAgAAABBFt+f+RL06J6mwtFrT3vrW6nAAAADiAsXwNui4Xun6+zWjld7Bpa93lOr8Z/+rVd/vtzosAAAAAFGS6LJr+i+GSpLmf7pNv3tzrfaV11gcFQAAQNtGMbyNGt2ns16/8SQNzErW3vIaXfrnT/TKZ9usDgsAAABAlIzu01nX1K0Z9Px/CnTK4x/o8cXrVFzpsTgyAACAtolieBuWk56kf9xwosYdkyWvz9Tdr32lB/71jcqYKQgAAADEhfvOPVp/ueo4DemeqkqPT39ctlknT/9AM5ZsUEkVeT8AAMDhMEzTNK0OItaUlpYqNTVVJSUlSklJsTqcH+X3m3rm/U168r0NkiSHzdBxvdJ1xtFddfrAruqT0UGGYYT2r/b6tP1Apb7fV6nURKdG9uwUdj0AAEC8amt5HqKnrZ970zS1ZG2RZizZoHWFZZIkl8OmwdkpGnZUmoblpGroUWnq3bmDbDZyewAA0H4cTp5HMbwJbTVRfuebQk1/e52+21sRtr1n5yQNPSpNRSXV2rq/UoWl1WHXn9AnXfedM0hDjkptzXABAABaXVvN83Dk4uXc+/2mFn9TqJnvbdCGovJG1ycnODTsqDQd1ytdx/XqpBE9OinRZbcgUgAAgNZBMfwItfVEuWBvhd5ft1sfrNutlQX75PU1PsUd3Q7lpCdp855yeWr9kqQLhmfrzrMGKCc9qbVDBgAAaBVtPc9D5OLt3JumqYK9Ffpqe4lWby/WV9tL9PWOEtXU5fZBDpuhY7qn6rhenXRi3wyd0KczxXEAABBXKIYfoXhKlMtravXRxr0q2Fuh7LQE9ezcQT3Sk9QpySnDMLSjuEpPvLNe//hyhyTJZbfpqpN66ZLjctTR7VCCw64El00uu41RKgAAoM2LpzwPh6c9nHuvz68NRWX64vsD+mzLAX22Zb92lYR/KtTlsGl073SdNqCrTv1JF/Xt0oE8HwAAtGkUw49Qe0iUD/b1jhI9+ta3+njzviavtxlSotOuAVnJOrl/F/20f4aG5aTJaWcNVgAA0Ha0xzwPAe3x3JumqR3FVfpsy359WrBfH27Yqx3FVWH7HNUpUcdkp6pXRgf16pxU97WDMlPcMgxDtT6/PD6/arx+1dT65bAbyujotugRAQAANEYx/Ai1x0RZCiTLy9bv0ZPvbdB3eypU5fXJ5z/0r0ey26ET+nbWyf0ylJOeqLQklzoludQpyamUBGeLLNzjqfUrf1ux8rcdUJdkN4sEAQCAw9Je8zxw7qVAvr95T7mWrd+j5Rv2aOV3++Xx+Zvc12k35DfV5OuBrJQEHdszTSNyOmlEjzQd0z1VCU5GrwAAAGtQDD9CJMr1vD6/qrw+VXt8Kq2u1arv9+vDjXv13017VVzpPeTtbIaUkuhUgsMut9MW+up22JTgtCvRaVeSy65El0NJrsD3yQkOpXdwq3MHl9LrLp06uPTdnnL9d9M+fbx5rz7fckBVXl/YfSUnODSke6qGHpWmY7qnqKPbIafdJrvNkNNuyG6zKcFpU2ZygtLqxsM0FJy3uLJgvz75bp8+K9ivWr+p/pkd1b9rsn6SmayfZHZU/8xkpSY6W+R5bg7TNLWzpFprtpdofWGZuqUm6IQ+nZWTnshHWwEAaCbyvPaLc99YpadWn285oM17yrVlb4W27KvUln0V2n6gqskiuMNmyGeaOvgVpNNuqHdGB6UluZSW6FRqolNpSYGvHd0OJbrsSnDaQ68DEpx2ldd4tbfMoz3lNdpbXqO95R4VV3rUNTlBfboEutN7Z3RQr4wkJbkcrfSMAACAtqjNFcNnzZql3//+9yosLNSwYcP0zDPP6Pjjjz/k/q+++qqmTJmiLVu2qH///po+fbrOOeec0PWmaer+++/X888/r+LiYp100kl67rnn1L9//2bFQ6L843x+U9/sLNF/Nu7VZ1v2a295jQ5UeFVS5VV5TW2L3nfnDi6N6tVJe8s9+mZniaq9TXezNCXRaVe31AR1S0tQt9REVXt9WlmwX3vKapp1+67JbvXp0kF9u3RU3y4dQ4l6da1P+8o9oUR+b3mNyqtrld7BpazUBGWlJCgzJUGZKW6ld3DJMAyZdS8kTAV+Z2tq/SqrrlVptVelVd66r7XatLtca3aUaM2OEu2v8DSKqVtqgkb3TtcJfTprVK90uR021dT65an1q6bWJ0+tX35T6tzRpa7JbqUmNn5DIKjK49OBSo8MQ0rv4JLb0XSHj6fWrx3FVfp+X4V2Flerc0eX+nXtqJ7pSXI0Y3SO329qb0WNdhyo0s7iau0srpLfNDWwW4oGZ6dE/aO3pmk2+w0Dv9+UKcnOpw0AIC6R57VfnPvm8/r82l1WI4fNkNthk8sRWEPIYbep0lOrr7aX6Mutxfpy6wF9sbVYe8ubl0tHKpjDJic41DEh8DW5rsje8NVs8KWty2ELFOaTnOpU9zUt0SW7zVC11xe41PpV7fUFRr/UPc4Epz301Wm3qabWpyqPL9Ac5A189fpMpSY6Q5+IDd4P4yMBALBOmyqGL1y4UBMmTNDs2bM1evRozZw5U6+++qrWr1+vrl27Ntr/448/1k9/+lNNmzZN//u//6uXX35Z06dP1xdffKFjjjlGkjR9+nRNmzZN8+bNU+/evTVlyhStWbNGa9euVUJCwo/GRKJ8ZDy1fhVXeVRa5VW1N1CQrfH6VV33tcrrU6UnkFhWenyq9NaqyuNTaZVX+yo82l932VfhkafWr+QEh07o01kn9u2sE/tm6CeZHUOFzVqfXxuKyvXV9mKt3l6s9YVlqqn1q9ZnqtbvV63fVK3PVKWnVgd+oJPdZbdpeI80nVBXVE502bWxqFwbisq0YXe5NhaVNVp8yAp2m6GfZCbr6Kxkbd1fqdXbi+X1Hd4/YZfdpi7JbnVJdivJZdeBSq+KKz06UOlp9MZCSoJDGR3dyugYKOKXVnu1dX9lXfG68bGddkM9O3dQvy4d1bNzkjw+v8qra1VWXavymlqV1dSquNKjXcXVh/xIriRlprg1ODtVg7NT1DUlQbU+v3x+U7V+M/DVZ8rlsIU+VdDBHfiEgcthU1Fptbbuq9L3+yu0bX+ltu6v1J6yGqV3cKlLcuANiczkBHVNcSvRZdfu0hoVlVarsLRaRSXV2l1WI8OQeqQnqU/dGx59MwJf/aa0s7hKO+ouO4urVFhSLbvNUEpCoPspJdFR92It8KLIYTPksBty2AKfUrAZkscXfLPCL2/d94ahQBdVokupSU6lJQZeXLkdNvlNU34z8ALPZ5ry+wMvUoPHCb3x4TPrivl1b7TUvdkiSYYkm02y1f3bsRmG7DZDLrut7lMbgefP7bCp2uvTzuJq7Siu1I4DVdpR94aFJGUku9Wlo1sZya7A145uOe22ui6xwPnx+QP373QYctnt9S+iG7yYTnDa5LLbQ9scdkN+vxn6OLZZ95gDjzdwzMDzYMrnl+w2hd3e5bDJaTdkmoHn11vrl9dnyusL/D9g1D3m4HMQfLMj+Nw1/L8q+LsZ+hU3JVOB591X9xgDv4t++fxSgtNWf+7quuGSExyy2erf9AqeQ3/dn9zgtuCbYYYR/B0JfG345o3Pb4ZegAdfwBuGEfh0jdOuRJf9kIscB59HT4MX/DW1vtAbZm5H+Ll3O21y2OpfzJsK/4duyJDNkAzDkCHJMCS/qcD/tz6z7v/cwL/Xmrrf8eD91Xj9qvX7legM/JvtWHfp4HbI5ai/T3/oXAfu32YYshuGjLr7PRzBxx/4/W/6tqZpylv3N8Nb929IdY/NkCEZwe8lh80mm02y1/0OBd/YDP5OBB9/rd+U3TDqf78POqcHx+fzm7IZgd/NSB4nDg95XvvFuW8Zpmlq+4Eqfb+vUiVVXhVXeVRcGWiSKa70qKKmvpBc5Q28Bqip9auD2x7KMwMXl1ISnSoqqVbB3goV7KvQd3sqVFJ16Bw+liQFu98dNrkbFNXdTf1c93fPb9b/3Qt23NuMwKdbA/lj4G+I3W7IF/w72+BvbqCZJtBIE2yqKauuld0w1L1TonLSk9QjPUk5dd8nOO2hvLy8bt9yT60cNiPUsZ/kcijRFfhkrymFcrBaXyBGmQr9fXOHvtplt0me2kDuFcxvPT6/bIahjgn1f/eDF5fDFvq7F8zNbM38GxjMjTx1M+yd9kB+2fBvvWkGnqP6/CeQ37kbxH2o/CnW+P0m+QEA/Ig2VQwfPXq0jjvuOD377LOSJL/fr5ycHN1888265557Gu1/ySWXqKKiQm+88UZo2wknnKDhw4dr9uzZMk1T2dnZuuOOO3TnnXdKkkpKSpSZmam5c+fq0ksv/dGYSJRjg2maqvT4lOC0R6VLt9rr066Sau0qrtLOkmoVlgSKe6N6pWt4TtqPzjksrfbquz0V2ry7XN/tLdfm3RXavKdcW/dXqoPboc4dXMro6FbnjoGvHd0O7avwBAqtJdUqKq3WviY6uxsKFFUdSkkMzF1PTnDoqE6JGtI9Vcd0T9XR3VLC4qzy+PTF1gNa+d0+ffLdfn21o1iS5HbYGySngWR7X4XnB0fbBDnqnuvaH5gXLwUKgD3TOyg7LUF7ymu0eXdFoxE2P8RmSJkpCcpOS1R2WqL8pqlvd5aqYF9Fo4/eAm2RYSji32WbITnstlChtjn7JzrtgYXO/P6wwn1bYK974+DHwg29YK57YyPwNfAC2m4YoRfrwWLBwc9dsOBsq6tuB9+8iZSt7s2AH2MYgTciXfbAm1uhN/YOceOD47QZB70RYaiuaFC/zW4YgTdtzPoiu99sWNw3QrEYdT833K/+TZv6mMK6LZsKtO4Ni4afcmq4n63BmyYN30CR6t5oaPD83HpGf/2/U/v++JMZBeR57Rfnvm06UOHR9gNVKqv2qqymrsmiOvBp1EqPr/7NS9X/H1dd69eBCo8OVHpVUuUJNX+YpgIF6YPGOPr9CjXuVDd4c9ztsCkx+OZz3RvQdptRV+j3an+FR6XVXnLXKAo2azRsonDaDdXU+sPeTDnUbZ32+oaH5vyNdgfvo66xIlhYd9gN1frrivu1ZqjZotZvymE3Qrerb8qwhX4Pgn8Tpbo3Nxw2OW2BYzsdNrnshiQj9Hc3+KaIz2+qutanyhqfKjy1qqipVYXHF2qcCd5fw5gddce12ww56hpx7EZgnFEwDwjlBMH4DvqFNQxDdptkt9lkr8sxAg0atro3Zuqfm0DOFnit6K/Lt3z+YHOHJBkNco3gseoahOqahOw2Q4YOylv8gRjDcxwj9H3wmDZb3b/2ujQi+CaR1xd4k8jr94dyn+BjC+1uBHJHhz382EHBPCb49NQ/D/Vfg2+4BONu2OASynnqcjbV5T6hHKlB3hQ8fv3jrI/VrGv+8ZtmWH4cfA6CP9Tni4Hb1n8fiCGUcxn1WZe/QRwNG3Xqzlzofho8xY3+j61/vhp83yADPPj/w9BzaLcFnv9AYhv4nW/QTOXzm3WPQ6GmE1vdOQtrUmnwmMJz2MbnIiwXbZB7Hhyv2eD7hkK/d0b4fTel4fN1qOeq4fENoz5Gqf5rw/8/mvu3peG5rr/PH75xw9+LQ73P1jDHb+q2DZ/j+tiD3we+Gdo9TT06JzXvgRyhw8nzLB2+5vF4tGrVKk2ePDm0zWazKTc3VytWrGjyNitWrFBeXl7YtrFjx2rRokWSpIKCAhUWFio3Nzd0fWpqqkaPHq0VK1Y0WQyvqalRTU39R/tKS0uP5GEhSgzDUAd39H5FE5x29c4IzB6MREqCU8Nz0jQ8Jy3iGDy1fpVUecOKEcH/RJz2QKfz4bzjn+iy66R+GTqpX0az9q+p9WlPWY32lNVod1mNqjy+0MdHOyW51KlDYK6jaQaK/8GxL8ERMB3cDvXsnKSe6UnqkuwOi9XvN7WzpEqb91Ro0+5ybT9QqUSnXR3rPsYa+OpUSqJT3VITlJWa0OTHSctrarVuV6m+2VmqtTtLVVbjDSVQDZMQb61flZ5AohhMGKu8PnVNdqtnegf16BzohOmRnqSuKW4dqPBqd1l1qBO8qKxalR6fuiYnKCvFHRhjUzfSxucPzJH/bk954OveQGeS3Waoe1qiuncKFPC7143b8ZlmYLRNVaALqrS6VmXVXnl94V3Etb5AUhpMmBsm0KapUAdVcZVXJZVeHaj0yOszm+yYCd22QVIcTFAb/goFf8caJmGhxNsv1fj8qqnrrAl2zTjtRt3jq3+sR6UlyjCkPWWB34nA18Al2AUb7LoOJmJenxk4bqiDvb4juWFXe1MFwYbFwKaKnj7T/MHbS2rQlR/4PQvvLg/cxt3EugZOu61RwS7UGRx8sWGrT6CrvL7QuS+u9IbeFDqSF8bBbu6DJTgDXWV+v6nqBl3sflOq8Pz4m1HBj4G7nXY5bIa8Pn/onPzYG2CHw2Yo1CkW7Dh3OwL3WeX1qaKumBF8MdvcgrRZ92kBn0yp+e+9hdQn/dF5rM19ykxTYV1pzTluNOO0ii/sH8EPP5Zo/v4BQeT48aFT3TpCscrnN1VS5VVZdf2nYg/+WuMN/A0IdilX1+UKwWKbUVfwsdXlOLU+fyiP9Pr98vlM2e2GnLbwdZFcDpuSExxKSXCGGmqSExzy+kxtO1CpbfuDlypt3V8pn9+s79Kuy9GTXA75zfpPoVV6GnwSTYE8LPDJKEP2ujzU6/PXPSZfWB4RynHrCr4uh021PrOusOtTWXWgwPtDDTQ+v6kqv++wmmwa3vZQOYWr7nXHwZ9ODf19PpxJP16p7LCjOzINc4nWvm8AiNT0XwxRj849rA6jEUuL4Xv37pXP51NmZmbY9szMTK1bt67J2xQWFja5f2FhYej64LZD7XOwadOm6cEHH4zoMQCHw+UIjCixitth11GdknRUpx9+Z84wVDf/0KV+jacVNclmM0LHPvUnXSKOsaPboVG90jWqV3rEx2hKt9REDVLzu8By0pP00yN4HGg+X11XSaTjMPz+QLeOx+cPdXs4bbZDjsVoaZ5af6hLrGFR37A1fhMs2LURKvI2HPFUN94l+LFlt6PxY6r11XdJBV80Bt84sTd488DtrJ/1eig+vxl6oyLsDZW6r6F3+ht0XfhNM/ScO2y2Rl0zP8br86uyJhB7fVdLfTdI8I7DOqcadJAEvw+Ozwl21Dd8I8RhM0KxHtw9Ut+lVNf5VPcYpMbdQcHbBzuhGnawBLumHA3eKAm+oRF4QyjwhpPXF3i+7HYjNGrFUfemSsMOnWCcvro1DIIdTmFdLwc9H35/fXdG8A2kYBd5UOCx1HdyH9xJFOxIOdQ/v4b/Lg/uFgp1K9X9bAbaxkPjboLPe30cCvveygWqEb/I8dEa7DZD6R1cSo+xgn2/rh2tDuGQgiPF6v+OB7thzVAzhccXXmh3141IDC7CmuRyyNmwe9sXeBPB4/PLNBV6Iz7YRR3q6K3LG0Oj3Lz+0O2DI16C3ztsRl0nd333d7CZoOHYQ0/d6MODOy0NNXxzwy+Pz5S3tr6ZoWGeGHxTJDhOruEoyESnPawR5OCmEl/dcxB8/vymGfrbHtZZfYhO0GBnem2D/CrYzOOtDbwhU9tg/KD94FyzrmEneCzzoL/9wTGXoWP6zFAeEuwqbZg7BjuGQx3zB3VVN+yWDub9wXE5wTwsKHi7YGy+YB5n1n8NCstnFBwFWNfU1OBTfcFO4VBXbIPcJxhfMPcMvB5o2C3f4HGa9Tls8Pe/Ppczwn4/Ao+lPjc9+JN5wc56v9lwv/Bc1pRCb2gd3DXdcB+F3aa+bTp4zKbywYN/CP6mBUZNhn8qMjgaKvz3p/68hRqY/PUjM+vjavgcNPw3VP86ouG58B+U+x7qFYoRTGJV/2/j4Lw5eD4PpWGMoW1m+L+1gxvVgvsEfxfCGrEOas469P2G59cN7/PgY4SPUz1093nD5yos16/7XQnGXPcUhT7VEYq1wb8jK+tfP4RluSVNnjw5rNu8tLRUOTk5FkYEAO1HIAn64TFFP8RmM5Rgs//oqKPW4nLYor4I7KE47DYl221KTjjyQqLdZgQ+Cq7Wex6ddptSk2xKVSwWQo/szRS7Efj0TqLLLsXk4wPiHzk+EJscdpscUUo3HHYdVg4Ynjfy9xkA2iNLi+EZGRmy2+0qKioK215UVKSsrKwmb5OVlfWD+we/FhUVqVu3bmH7DB8+vMljut1uud2x+W4FAAAAgMNHjg8AAICDHfrz0q3A5XJp5MiRWrp0aWib3+/X0qVLNWbMmCZvM2bMmLD9JWnJkiWh/Xv37q2srKywfUpLS7Vy5cpDHhMAAAAAAAAAEN8sH5OSl5eniRMnatSoUTr++OM1c+ZMVVRUaNKkSZKkCRMmqHv37po2bZok6dZbb9Wpp56qJ554Queee64WLFigzz//XH/+858lBWbw3HbbbXrkkUfUv39/9e7dW1OmTFF2drYuvPBCqx4mAAAAAAAAAMBClhfDL7nkEu3Zs0dTp05VYWGhhg8frsWLF4cWwNy6datstvoG9hNPPFEvv/yyfvvb3+ree+9V//79tWjRIh1zzDGhfe6++25VVFTouuuuU3FxsU4++WQtXrxYCQkJrf74AAAAAAAAAADWM0zzh9ZDbZ9KS0uVmpqqkpISpaSkWB0OAAAAooQ8r/3i3AMAAMSnw8nzLJ0ZDgAAAAAAAABAa6AYDgAAAAAAAACIexTDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLjnsDqAWGSapiSptLTU4kgAAAAQTcH8Lpjvof0gxwcAAIhPh5PjUwxvQllZmSQpJyfH4kgAAADQEsrKypSammp1GGhF5PgAAADxrTk5vmHSFtOI3+/Xzp07lZycLMMwWuU+S0tLlZOTo23btiklJaVV7hMth/MZfzin8YXzGX84p/GlJc+naZoqKytTdna2bDYmBrYn5Pg4UpzP+MM5jS+cz/jDOY0vsZLj0xneBJvNpqOOOsqS+05JSeEfeBzhfMYfzml84XzGH85pfGmp80lHePtEjo9o4XzGH85pfOF8xh/OaXyxOsenHQYAAAAAAAAAEPcohgMAAAAAAAAA4h7F8Bjhdrt1//33y+12Wx0KooDzGX84p/GF8xl/OKfxhfOJeMHvcnzhfMYfzml84XzGH85pfImV88kCmgAAAAAAAACAuEdnOAAAAAAAAAAg7lEMBwAAAAAAAADEPYrhAAAAAAAAAIC4RzEcAAAAAAAAABD3KIbHgFmzZqlXr15KSEjQ6NGj9emnn1odEppp2rRpOu6445ScnKyuXbvqwgsv1Pr168P2qa6u1o033qjOnTurY8eO+sUvfqGioiKLIsbheOyxx2QYhm677bbQNs5n27Njxw5dccUV6ty5sxITEzVkyBB9/vnnoetN09TUqVPVrVs3JSYmKjc3Vxs3brQwYhyKz+fTlClT1Lt3byUmJqpv3756+OGH1XAtcM5nbPvwww913nnnKTs7W4ZhaNGiRWHXN+f87d+/X+PHj1dKSorS0tL0q1/9SuXl5a34KIDmIcdvu8jx4xs5fttHfh9fyPHbvraW41MMt9jChQuVl5en+++/X1988YWGDRumsWPHavfu3VaHhmZYvny5brzxRn3yySdasmSJvF6vzjrrLFVUVIT2uf322/Xvf/9br776qpYvX66dO3fq5z//uYVRozk+++wz/elPf9LQoUPDtnM+25YDBw7opJNOktPp1Ntvv621a9fqiSeeUKdOnUL7PP7443r66ac1e/ZsrVy5Uh06dNDYsWNVXV1tYeRoyvTp0/Xcc8/p2Wef1bfffqvp06fr8ccf1zPPPBPah/MZ2yoqKjRs2DDNmjWryeubc/7Gjx+vb775RkuWLNEbb7yhDz/8UNddd11rPQSgWcjx2zZy/PhFjt/2kd/HH3L8tq/N5fgmLHX88cebN954Y+hnn89nZmdnm9OmTbMwKkRq9+7dpiRz+fLlpmmaZnFxsel0Os1XX301tM+3335rSjJXrFhhVZj4EWVlZWb//v3NJUuWmKeeeqp56623mqbJ+WyLfvOb35gnn3zyIa/3+/1mVlaW+fvf/z60rbi42HS73eb8+fNbI0QchnPPPde8+uqrw7b9/Oc/N8ePH2+aJuezrZFk/vOf/wz93Jzzt3btWlOS+dlnn4X2efvtt03DMMwdO3a0WuzAjyHHjy/k+PGBHD8+kN/HH3L8+NIWcnw6wy3k8Xi0atUq5ebmhrbZbDbl5uZqxYoVFkaGSJWUlEiS0tPTJUmrVq2S1+sNO8cDBw5Ujx49OMcx7MYbb9S5554bdt4kzmdb9K9//UujRo3SRRddpK5du2rEiBF6/vnnQ9cXFBSosLAw7JympqZq9OjRnNMYdOKJJ2rp0qXasGGDJGn16tX66KOPNG7cOEmcz7auOedvxYoVSktL06hRo0L75ObmymazaeXKla0eM9AUcvz4Q44fH8jx4wP5ffwhx49vsZjjO6J+RDTb3r175fP5lJmZGbY9MzNT69atsygqRMrv9+u2227TSSedpGOOOUaSVFhYKJfLpbS0tLB9MzMzVVhYaEGU+DELFizQF198oc8++6zRdZzPtue7777Tc889p7y8PN1777367LPPdMstt8jlcmnixImh89bU/8Oc09hzzz33qLS0VAMHDpTdbpfP59Pvfvc7jR8/XpI4n21cc85fYWGhunbtGna9w+FQeno65xgxgxw/vpDjxwdy/PhBfh9/yPHjWyzm+BTDgSi58cYb9fXXX+ujjz6yOhREaNu2bbr11lu1ZMkSJSQkWB0OosDv92vUqFF69NFHJUkjRozQ119/rdmzZ2vixIkWR4fD9corr+jvf/+7Xn75ZQ0ePFj5+fm67bbblJ2dzfkEALQIcvy2jxw/vpDfxx9yfLQ2xqRYKCMjQ3a7vdEq1UVFRcrKyrIoKkTipptu0htvvKEPPvhARx11VGh7VlaWPB6PiouLw/bnHMemVatWaffu3Tr22GPlcDjkcDi0fPlyPf3003I4HMrMzOR8tjHdunXToEGDwrYdffTR2rp1qySFzhv/D7cNd911l+655x5deumlGjJkiK688krdfvvtmjZtmiTOZ1vXnPOXlZXVaAHC2tpa7d+/n3OMmEGOHz/I8eMDOX58Ib+PP+T48S0Wc3yK4RZyuVwaOXKkli5dGtrm9/u1dOlSjRkzxsLI0Fymaeqmm27SP//5T73//vvq3bt32PUjR46U0+kMO8fr16/X1q1bOccx6IwzztCaNWuUn58fuowaNUrjx48Pfc/5bFtOOukkrV+/Pmzbhg0b1LNnT0lS7969lZWVFXZOS0tLtXLlSs5pDKqsrJTNFp662O12+f1+SZzPtq4552/MmDEqLi7WqlWrQvu8//778vv9Gj16dKvHDDSFHL/tI8ePL+T48YX8Pv6Q48e3mMzxo74kJw7LggULTLfbbc6dO9dcu3ated1115lpaWlmYWGh1aGhGa6//nozNTXVXLZsmblr167QpbKyMrTPr3/9a7NHjx7m+++/b37++efmmDFjzDFjxlgYNQ5Hw5XmTZPz2dZ8+umnpsPhMH/3u9+ZGzduNP/+97+bSUlJ5t/+9rfQPo899piZlpZmvv766+ZXX31lXnDBBWbv3r3NqqoqCyNHUyZOnGh2797dfOONN8yCggLzH//4h5mRkWHefffdoX04n7GtrKzM/PLLL80vv/zSlGTOmDHD/PLLL83vv//eNM3mnb+zzz7bHDFihLly5Urzo48+Mvv3729edtllVj0koEnk+G0bOX78I8dvu8jv4w85ftvX1nJ8iuEx4JlnnjF79Ohhulwu8/jjjzc/+eQTq0NCM0lq8vKXv/wltE9VVZV5ww03mJ06dTKTkpLMn/3sZ+auXbusCxqH5eBEmfPZ9vz73/82jznmGNPtdpsDBw40//znP4dd7/f7zSlTppiZmZmm2+02zzjjDHP9+vUWRYsfUlpaat56661mjx49zISEBLNPnz7mfffdZ9bU1IT24XzGtg8++KDJv5sTJ040TbN552/fvn3mZZddZnbs2NFMSUkxJ02aZJaVlVnwaIAfRo7fdpHjxz9y/LaN/D6+kOO3fW0txzdM0zSj328OAAAAAAAAAEDsYGY4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQARWbZsmQzDUHFxsdWhAAAAAIgCcnwA8Y5iOAAAAAAAAAAg7lEMBwAAAAAAAADEPYrhANBG+f1+TZs2Tb1791ZiYqKGDRum//u//5NU//HGN998U0OHDlVCQoJOOOEEff3112HHeO211zR48GC53W716tVLTzzxRNj1NTU1+s1vfqOcnBy53W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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BgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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w5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "# Imports\n", + "import csv\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "\n", + "path = \"project/models/benzene_dft_script/log.csv\"\n", + "\n", + "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", + "data_dict = {}\n", + "\n", + "with open(path, 'r') as file:\n", + " reader = csv.reader(file)\n", + "\n", + " # Extract the headers (keys) from the first row\n", + " headers = next(reader)\n", "\n", - "import matplotlib.pyplot as plt" + " # Initialize empty lists for each key\n", + " for header in headers:\n", + " data_dict[header] = []\n", + "\n", + " # Read the rest of the rows and append values to the corresponding key\n", + " for row in reader:\n", + " for idx, value in enumerate(row):\n", + " key = headers[idx]\n", + " data_dict[key].append(float(value))\n", + "\n", + "for key in keys:\n", + " fig, axes = plt.subplots(1, 2, sharey=True, sharex=True, figsize=(18, 4))\n", + "\n", + " val = np.array(data_dict[f\"val_{key}\"])\n", + " train = np.array(data_dict[f\"train_{key}\"])\n", + " epoch = np.array(data_dict[\"epoch\"])\n", + "\n", + " axes[0].plot(epoch, val)\n", + " axes[1].plot(epoch, train)\n", + "\n", + " axes[0].set_ylabel(f\"val_{key}\")\n", + " axes[0].set_xlabel(r\"epoch\")\n", + " axes[1].set_ylabel(f\"train_{key}\")\n", + " axes[1].set_xlabel(r\"epoch\")\n", + " fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Evaluation\n", - "==========\n", + "## Evaluation\n", "\n", "After the training is completed and we are satisfied with our choice of hyperparameters and vadliation loss, we can evaluate the model on the test set.\n", - "We provide a separate command for test set evaluation:\n", - "\n", - "`apax evaluate config_minimal.yaml`\n", + "We provide a separate command for test set evaluation:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mUsage: \u001b[0mapax [OPTIONS] COMMAND [ARGS]...\n", + "\u001b[2mTry \u001b[0m\u001b[2;34m'apax \u001b[0m\u001b[1;2;34m-h\u001b[0m\u001b[2;34m'\u001b[0m\u001b[2m for help.\u001b[0m\n", + "\u001b[31m╭─\u001b[0m\u001b[31m Error \u001b[0m\u001b[31m─────────────────────────────────────────────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", + "\u001b[31m│\u001b[0m No such command 'evaluate'. \u001b[31m│\u001b[0m\n", + "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + } + ], + "source": [ + "!apax evaluate config_minimal.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "TODO pretty print results to the terminal\n", "\n", @@ -230,6 +478,22 @@ "cell_type": "markdown", "metadata": {}, "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To remove all the created files and clean up yor working directory run" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "!rm -r project config.yaml error_config.yaml" + ] } ], "metadata": { diff --git a/tests/conftest.py b/tests/conftest.py index ad74cc70..e2d93738 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,9 +12,9 @@ from apax.config.train_config import Config from apax.model.builder import ModelBuilder from apax.train.run import run -from apax.utils.random import seed_py_np_tf from apax.utils.datasets import download_md22_stachyose from apax.utils.helpers import mod_config +from apax.utils.random import seed_py_np_tf @pytest.fixture(autouse=True) From 8ad0e3bdd3bd8e14ae7cc04ddb8596d7b759204b Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Sat, 2 Mar 2024 13:12:07 +0100 Subject: [PATCH 076/192] Metrics plot clean up training params eval --- examples/01_Model_Training.ipynb | 320 +++++++++++++------------------ 1 file changed, 129 insertions(+), 191 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 46f0c786..e05f85fe 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -44,49 +44,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1m \u001b[0m\n", - "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mapax [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m\n", - "\u001b[1m \u001b[0m\n", - "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-version\u001b[0m \u001b[1;32m-V\u001b[0m \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m Install completion for the current shell. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m Show completion for the current shell, to \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m copy it or customize the installation. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m \u001b[1;32m-h\u001b[0m Show this message and exit. \u001b[2m│\u001b[0m\n", - "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", - "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mdocs \u001b[0m\u001b[1;36m \u001b[0m Opens the documentation website in your browser. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36meval \u001b[0m\u001b[1;36m \u001b[0m Starts performing the evaluation of the test dataset with \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mvalidate \u001b[0m\u001b[1;36m \u001b[0m Validate training or MD config files. \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36mvisualize\u001b[0m\u001b[1;36m \u001b[0m Visualize a model based on a configuration file. A CO molecule is \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m taken as sample input (influences number of atoms, number of \u001b[2m│\u001b[0m\n", - "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m species is set to 10). \u001b[2m│\u001b[0m\n", - "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "!apax -h" ] @@ -100,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -132,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -168,18 +128,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32mSuccess!\u001b[0m\n", - "config.yaml is a valid training config.\n" - ] - } - ], + "outputs": [], "source": [ "!apax validate train config.yaml" ] @@ -194,7 +145,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -209,21 +160,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 validation error for Config\n", - "n_epochs\n", - " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", - " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", - "\u001b[31mConfiguration Invalid!\u001b[0m\n" - ] - } - ], + "outputs": [], "source": [ "!apax validate train error_config.yaml" ] @@ -239,32 +178,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO | 21:56:40 | Initializing Callbacks\n", - "INFO | 21:56:40 | Initializing Loss Function\n", - "INFO | 21:56:40 | Initializing Metrics\n", - "INFO | 21:56:40 | Running Input Pipeline\n", - "INFO | 21:56:40 | Read data file project/benzene_mod.xyz\n", - "INFO | 21:56:40 | Loading data from project/benzene_mod.xyz\n", - "INFO | 21:56:50 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13135.40it/s]\n", - "INFO | 21:56:50 | Computing per element energy regression.\n", - "INFO | 21:56:57 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12868.33it/s]\n", - "INFO | 21:56:57 | Initializing Model\n", - "INFO | 21:56:58 | initializing 1 models\n", - "INFO | 21:57:04 | Initializing Optimizer\n", - "INFO | 21:57:04 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" - ] - } - ], + "outputs": [], "source": [ "!apax train config.yaml" ] @@ -287,24 +203,14 @@ "\n", "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint.\n", "\n", - "Furthermore, an Apax trianing can easily be started within a scriped." + "Furthermore, an Apax trianing can easily be started within a script." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 10410.16it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11413.38it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:43<00:00, 2.24s/it, val_loss=0.31]\n" - ] - } - ], + "outputs": [], "source": [ "from apax.train.run import run\n", "\n", @@ -328,50 +234,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWD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Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAA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3W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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BgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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w5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABA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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import csv\n", "import matplotlib.pyplot as plt\n", @@ -399,21 +264,22 @@ " key = headers[idx]\n", " data_dict[key].append(float(value))\n", "\n", - "for key in keys:\n", - " fig, axes = plt.subplots(1, 2, sharey=True, sharex=True, figsize=(18, 4))\n", + "fig, axes = plt.subplots(2, 2, constrained_layout=True)\n", + "axes = axes.ravel()\n", + "fig.suptitle(f'Metrics', fontsize=16)\n", "\n", + "for id, key in enumerate(keys):\n", " val = np.array(data_dict[f\"val_{key}\"])\n", " train = np.array(data_dict[f\"train_{key}\"])\n", " epoch = np.array(data_dict[\"epoch\"])\n", "\n", - " axes[0].plot(epoch, val)\n", - " axes[1].plot(epoch, train)\n", + " axes[id].plot(epoch, val, label=\"val data\")\n", + " axes[id].plot(epoch, train, label=\"train data\")\n", "\n", - " axes[0].set_ylabel(f\"val_{key}\")\n", - " axes[0].set_xlabel(r\"epoch\")\n", - " axes[1].set_ylabel(f\"train_{key}\")\n", - " axes[1].set_xlabel(r\"epoch\")\n", - " fig.show()" + " axes[id].set_ylabel(f\"{key}\")\n", + " axes[id].set_xlabel(r\"epoch\")\n", + "\n", + "plt.show()" ] }, { @@ -428,31 +294,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mUsage: \u001b[0mapax [OPTIONS] COMMAND [ARGS]...\n", - "\u001b[2mTry \u001b[0m\u001b[2;34m'apax \u001b[0m\u001b[1;2;34m-h\u001b[0m\u001b[2;34m'\u001b[0m\u001b[2m for help.\u001b[0m\n", - "\u001b[31m╭─\u001b[0m\u001b[31m Error \u001b[0m\u001b[31m─────────────────────────────────────────────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", - "\u001b[31m│\u001b[0m No such command 'evaluate'. \u001b[31m│\u001b[0m\n", - "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - } - ], + "outputs": [], "source": [ - "!apax evaluate config_minimal.yaml" + "from apax.train.eval import eval_model\n", + "\n", + "eval_model(config_dict, n_test=100)\n", + "# !apax eval config.yaml" ] }, { @@ -471,14 +320,96 @@ "source": [ "## A Closer Look At Training Parameters\n", "\n", - "TODO" + "```yaml\n", + "n_epochs: # Number of training epochs.\n", + "seed: 1 # Seed for initialising random numbers\n", + "patience: None # Number of epochs without improvement before trainings gets terminated.\n", + "n_models: 1 # Number of models to be trained at once.\n", + "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. Can yield singificant speedups for small structures or small batch sizes.\n", + "\n", + "data:\n", + " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", + " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", + " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", + " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", + " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", + " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", + "\n", + " n_train: 1000 # Number of training datapoints from `data_path`.\n", + " n_valid: 100 # Number of validation datapoints from `data_path`.\n", + "\n", + " batch_size: 32 # Number of training examples to be evaluated at once.\n", + " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", + "\n", + " shift_method: \"per_element_regression_shift\"\n", + " shift_options:\n", + " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", + " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", + "\n", + " pos_unit: Ang\n", + " energy_unit: eV\n", + "\n", + " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", + "\n", + "model:\n", + " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", + " n_radial: 5 # Number of contracted basis functions.\n", + " nn: [512, 512] # Number of hidden layers and units in those layers.\n", + "\n", + " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", + " r_min: 0.5 # Cutoff radius of the descriptor.\n", + "\n", + " use_zbl: false # \n", + "\n", + " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", + " descriptor_dtype: fp64\n", + " readout_dtype: fp32\n", + " scale_shift_dtype: fp32\n", + "\n", + "loss:\n", + "- loss_type: structures # Weighting scheme for atomic contributions. See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", + " name: energy # Keyword of the quantity e.g `energy`.\n", + " weight: 1.0 # Weighting factor in the overall loss function.\n", + "- loss_type: structures\n", + " name: forces\n", + " weight: 4.0\n", + "\n", + "metrics:\n", + "- name: energy # Keyword of the quantity e.g `energy`.\n", + " reductions: # List of reductions performed on the difference between target and predictions. Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", + " - mae\n", + "- name: forces\n", + " reductions:\n", + " - mae\n", + " - mse\n", + "\n", + "optimizer:\n", + " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", + " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", + " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", + " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", + " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", + " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", + " zbl_lr: 0.001 # \n", + " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", + "\n", + "callbacks:\n", + "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", + "\n", + "progress_bar:\n", + " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", + " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", + "\n", + "\n", + "checkpoints:\n", + " ckpt_interval: 1 # Number of epochs between checkpoints.\n", + " # The options below are used for transfer learning\n", + " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", + " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", + "\n", + "```" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -488,12 +419,19 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "!rm -r project config.yaml error_config.yaml" + "# !rm -r project config.yaml error_config.yaml" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From b9172eacf2fe65ebac2a3e11147285b781353357 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 07:10:59 +0100 Subject: [PATCH 077/192] update training example --- apax/utils/datasets.py | 7 +- examples/01_Model_Training.ipynb | 273 ++++++++++++++++++++++++------- 2 files changed, 215 insertions(+), 65 deletions(-) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index b6935037..48b97d8f 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -2,7 +2,6 @@ import urllib import zipfile - def download_md22_stachyose(data_path): url = "http://www.quantum-machine.org/gdml/repo/static/md22_stachyose.zip" file_path = data_path / "md22_stachyose.zip" @@ -20,7 +19,7 @@ def download_md22_stachyose(data_path): return file_path -def download_md17_benzene_DFT(data_path): +def download_benzene_DFT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip" file_path = data_path / "benzene2018_dft.zip" @@ -36,7 +35,7 @@ def download_md17_benzene_DFT(data_path): return new_file_path -def download_md17_benzene_CCSDT(data_path): +def download_md22_benzene_CCSDT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene_ccsd_t.zip" file_path = data_path / "benzene_ccsdt.zip" @@ -63,7 +62,7 @@ def modify_xyz_file(file_path, target_string, replacement_string): return new_file_path -def mod_md17(file_path): +def mod_md_datasets(file_path): new_file_path = file_path.with_name(file_path.stem + "_mod" + file_path.suffix) with open(file_path, "r") as input_file, open(new_file_path, "w") as output_file: for line in input_file: diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index e05f85fe..913956e9 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -11,7 +11,7 @@ "\n", "## Acquiring a dataset\n", "\n", - "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mop_md17` function in order to be readable." + "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://sgdml.org/?datasetID=benzene2018_dft). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mod_md_datasets` function in order to be readable." ] }, { @@ -21,12 +21,12 @@ "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_md17_benzene_DFT, mod_md17\n", + "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets, download_md22_benzene_CCSDT\n", "\n", "data_path = Path(\"project\")\n", "\n", - "file_path = download_md17_benzene_DFT(data_path)\n", - "file_path = mod_md17(file_path)" + "file_path = download_benzene_DFT(data_path)\n", + "file_path = mod_md_datasets(file_path)" ] }, { @@ -60,9 +60,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "There is already a config file in the working directory.\n" + ] + } + ], "source": [ "!apax template train" ] @@ -92,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -145,7 +161,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -160,9 +176,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 validation error for Config\n", + "n_epochs\n", + " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", + " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", + "\u001b[31mConfiguration Invalid!\u001b[0m\n" + ] + } + ], "source": [ "!apax validate train error_config.yaml" ] @@ -211,6 +239,47 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [ + "from ase.units import kcal, mol, Ang\n", + "from ase.io import read, write\n", + "from ase.calculators.singlepoint import SinglePointCalculator\n", + "atoms = read(file_path, \":\")\n", + "for atom in atoms:\n", + " energy = atom.get_total_energy() * kcal/mol\n", + " forces = atom.get_forces() * kcal/mol/Ang\n", + " calc = SinglePointCalculator(atoms, energy=energy, forces=forces)\n", + " atom.calc = calc\n", + "write(file_path, atoms) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12911.35it/s]\n" + ] + }, + { + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 18\u001b[0m\n\u001b[1;32m 5\u001b[0m config_updates \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mn_epochs\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m100\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdata\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 13\u001b[0m }\n\u001b[1;32m 14\u001b[0m }\n\u001b[1;32m 16\u001b[0m config_dict \u001b[38;5;241m=\u001b[39m mod_config(config_path, config_updates)\n\u001b[0;32m---> 18\u001b[0m \u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig_dict\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/uni/dev/apax/apax/train/run.py:70\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(user_config, log_level)\u001b[0m\n\u001b[1;32m 68\u001b[0m train_raw_ds, val_raw_ds \u001b[38;5;241m=\u001b[39m load_data_files(config\u001b[38;5;241m.\u001b[39mdata)\n\u001b[1;32m 69\u001b[0m train_ds, ds_stats \u001b[38;5;241m=\u001b[39m initialize_dataset(config, train_raw_ds)\n\u001b[0;32m---> 70\u001b[0m val_ds \u001b[38;5;241m=\u001b[39m \u001b[43minitialize_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mval_raw_ds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcalc_stats\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 72\u001b[0m train_ds\u001b[38;5;241m.\u001b[39mset_batch_size(config\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39mbatch_size)\n\u001b[1;32m 73\u001b[0m val_ds\u001b[38;5;241m.\u001b[39mset_batch_size(config\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39mvalid_batch_size)\n", + "File \u001b[0;32m~/uni/dev/apax/apax/data/initialization.py:51\u001b[0m, in \u001b[0;36minitialize_dataset\u001b[0;34m(config, atoms_list, read_labels, calc_stats)\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m calc_stats \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m read_labels:\n\u001b[1;32m 48\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 49\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCannot calculate scale/shift parameters without reading labels.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 50\u001b[0m )\n\u001b[0;32m---> 51\u001b[0m inputs \u001b[38;5;241m=\u001b[39m \u001b[43mprocess_inputs\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 52\u001b[0m \u001b[43m \u001b[49m\u001b[43matoms_list\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 53\u001b[0m \u001b[43m \u001b[49m\u001b[43mr_max\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mr_max\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 54\u001b[0m \u001b[43m \u001b[49m\u001b[43mdisable_pbar\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprogress_bar\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdisable_nl_pbar\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 55\u001b[0m \u001b[43m \u001b[49m\u001b[43mpos_unit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpos_unit\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 56\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 57\u001b[0m labels \u001b[38;5;241m=\u001b[39m atoms_to_labels(\n\u001b[1;32m 58\u001b[0m atoms_list,\n\u001b[1;32m 59\u001b[0m additional_properties_info\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39madditional_properties_info,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 62\u001b[0m energy_unit\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39menergy_unit,\n\u001b[1;32m 63\u001b[0m )\n\u001b[1;32m 65\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m calc_stats:\n", + "File \u001b[0;32m~/uni/dev/apax/apax/data/input_pipeline.py:105\u001b[0m, in \u001b[0;36mprocess_inputs\u001b[0;34m(atoms_list, r_max, disable_pbar, pos_unit)\u001b[0m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mprocess_inputs\u001b[39m(\n\u001b[1;32m 100\u001b[0m atoms_list: \u001b[38;5;28mlist\u001b[39m,\n\u001b[1;32m 101\u001b[0m r_max: \u001b[38;5;28mfloat\u001b[39m,\n\u001b[1;32m 102\u001b[0m disable_pbar\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m 103\u001b[0m pos_unit: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAng\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 104\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mdict\u001b[39m:\n\u001b[0;32m--> 105\u001b[0m inputs \u001b[38;5;241m=\u001b[39m \u001b[43matoms_to_inputs\u001b[49m\u001b[43m(\u001b[49m\u001b[43matoms_list\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpos_unit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 106\u001b[0m idx, offsets \u001b[38;5;241m=\u001b[39m dataset_neighborlist(\n\u001b[1;32m 107\u001b[0m inputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpositions\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[1;32m 108\u001b[0m box\u001b[38;5;241m=\u001b[39minputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfixed\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbox\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 111\u001b[0m disable_pbar\u001b[38;5;241m=\u001b[39mdisable_pbar,\n\u001b[1;32m 112\u001b[0m )\n\u001b[1;32m 114\u001b[0m inputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124midx\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m idx\n", + "File \u001b[0;32m~/uni/dev/apax/apax/utils/convert.py:75\u001b[0m, in \u001b[0;36matoms_to_inputs\u001b[0;34m(atoms_list, pos_unit)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Converts an list of ASE atoms to a dict where all inputs\u001b[39;00m\n\u001b[1;32m 49\u001b[0m \u001b[38;5;124;03mare sorted by their shape (ragged/fixed). Units are\u001b[39;00m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;124;03madjusted if ASE compatible and provided in the inputpipeline.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[38;5;124;03m Labels are trainable system properties.\u001b[39;00m\n\u001b[1;32m 63\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 64\u001b[0m inputs \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 65\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\n\u001b[1;32m 66\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpositions\u001b[39m\u001b[38;5;124m\"\u001b[39m: [],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 72\u001b[0m },\n\u001b[1;32m 73\u001b[0m }\n\u001b[0;32m---> 75\u001b[0m box \u001b[38;5;241m=\u001b[39m \u001b[43matoms_list\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241m.\u001b[39mcell\u001b[38;5;241m.\u001b[39marray\n\u001b[1;32m 76\u001b[0m pbc \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mall(box \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1e-6\u001b[39m)\n\u001b[1;32m 78\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m atoms \u001b[38;5;129;01min\u001b[39;00m atoms_list:\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" + ] + } + ], "source": [ "from apax.train.run import run\n", "\n", @@ -219,7 +288,7 @@ "config_updates = {\n", " \"n_epochs\": 100,\n", " \"data\": {\n", - " \"experiment\": \"benzene_dft_script\",\n", + " \"experiment\": \"benzene_dft_script2\",\n", " \"directory\": \"project/models\",\n", " \"data_path\": str(file_path),\n", " \"energy_unit\": \"kcal/mol\",\n", @@ -243,7 +312,7 @@ "import numpy as np\n", "\n", "\n", - "path = \"project/models/benzene_dft_script/log.csv\"\n", + "path = \"project/models/benzene_dft_script2/log.csv\"\n", "\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", "data_dict = {}\n", @@ -274,7 +343,7 @@ " epoch = np.array(data_dict[\"epoch\"])\n", "\n", " axes[id].plot(epoch, val, label=\"val data\")\n", - " axes[id].plot(epoch, train, label=\"train data\")\n", + " # axes[id].plot(epoch, train, label=\"train data\")\n", "\n", " axes[id].set_ylabel(f\"{key}\")\n", " axes[id].set_xlabel(r\"epoch\")\n", @@ -321,62 +390,65 @@ "## A Closer Look At Training Parameters\n", "\n", "```yaml\n", - "n_epochs: # Number of training epochs.\n", - "seed: 1 # Seed for initialising random numbers\n", - "patience: None # Number of epochs without improvement before trainings gets terminated.\n", - "n_models: 1 # Number of models to be trained at once.\n", - "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. Can yield singificant speedups for small structures or small batch sizes.\n", + "n_epochs: # Number of training epochs.\n", + "seed: 1 # Seed for initialising random numbers\n", + "patience: None # Number of epochs without improvement before trainings gets terminated.\n", + "n_models: 1 # Number of models to be trained at once.\n", + "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. \n", + " # Can yield singificant speedups for small structures or small batch sizes.\n", "\n", "data:\n", - " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", - " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", - " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", - " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", - " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", - " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", + " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", + " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", + " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", + " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", + " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", + " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", "\n", - " n_train: 1000 # Number of training datapoints from `data_path`.\n", - " n_valid: 100 # Number of validation datapoints from `data_path`.\n", + " n_train: 1000 # Number of training datapoints from `data_path`.\n", + " n_valid: 100 # Number of validation datapoints from `data_path`.\n", "\n", - " batch_size: 32 # Number of training examples to be evaluated at once.\n", - " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", + " batch_size: 32 # Number of training examples to be evaluated at once.\n", + " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", "\n", " shift_method: \"per_element_regression_shift\"\n", " shift_options:\n", - " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", - " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", + " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", + " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", "\n", " pos_unit: Ang\n", " energy_unit: eV\n", "\n", - " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", + " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", "\n", "model:\n", - " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", - " n_radial: 5 # Number of contracted basis functions.\n", - " nn: [512, 512] # Number of hidden layers and units in those layers.\n", + " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", + " n_radial: 5 # Number of contracted basis functions.\n", + " nn: [512, 512] # Number of hidden layers and units in those layers.\n", "\n", - " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", - " r_min: 0.5 # Cutoff radius of the descriptor.\n", + " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", + " r_min: 0.5 # Cutoff radius of the descriptor.\n", "\n", - " use_zbl: false # \n", + " use_zbl: false # \n", "\n", - " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", + " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", " descriptor_dtype: fp64\n", " readout_dtype: fp32\n", " scale_shift_dtype: fp32\n", "\n", "loss:\n", - "- loss_type: structures # Weighting scheme for atomic contributions. See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", - " name: energy # Keyword of the quantity e.g `energy`.\n", - " weight: 1.0 # Weighting factor in the overall loss function.\n", + "- loss_type: structures # Weighting scheme for atomic contributions.\n", + " # See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", + " name: energy # Keyword of the quantity e.g `energy`.\n", + " weight: 1.0 # Weighting factor in the overall loss function.\n", "- loss_type: structures\n", " name: forces\n", " weight: 4.0\n", "\n", "metrics:\n", - "- name: energy # Keyword of the quantity e.g `energy`.\n", - " reductions: # List of reductions performed on the difference between target and predictions. Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", + "- name: energy # Keyword of the quantity e.g `energy`.\n", + " reductions: # List of reductions performed on the difference between target and predictions.\n", + " # Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", " - mae\n", "- name: forces\n", " reductions:\n", @@ -384,32 +456,103 @@ " - mse\n", "\n", "optimizer:\n", - " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", - " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", - " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", - " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", - " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", - " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", - " zbl_lr: 0.001 # \n", - " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", + " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", + " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", + " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", + " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", + " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", + " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", + " zbl_lr: 0.001 # \n", + " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", "\n", "callbacks:\n", - "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", + "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", "\n", "progress_bar:\n", - " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", - " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", + " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", + " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", "\n", "\n", "checkpoints:\n", - " ckpt_interval: 1 # Number of epochs between checkpoints.\n", - " # The options below are used for transfer learning\n", - " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", - " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", + " ckpt_interval: 1 # Number of epochs between checkpoints.\n", + " \n", + " # The options below are used for transfer learning\n", + " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", + " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", "\n", "```" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Default Value | Description |\n", + "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", + "| **n_epochs** | `` | Number of training epochs. |\n", + "| **seed** | 1 | Seed for initializing random numbers. |\n", + "| **patience** | None | Number of epochs without improvement before training termination. |\n", + "| **n_models** | 1 | Number of models trained simultaneously. |\n", + "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", + "| **Data** | | |\n", + "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", + "| experiment | apax | Model name distinguishing from others in directory. |\n", + "| data_path | `` | Path to single dataset file. |\n", + "| train_data_path | `` | Path to training dataset. |\n", + "| val_data_path | `` | Path to validation dataset. |\n", + "| test_data_path | `` | Path to test dataset. |\n", + "| n_train | 1000 | Number of training data points. |\n", + "| n_valid | 100 | Number of validation data points. |\n", + "| batch_size | 32 | Number of training examples evaluated at once. |\n", + "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", + "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", + "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", + "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", + "| pos_unit | Ang | Positional unit. |\n", + "| energy_unit | eV | Energy unit. |\n", + "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", + "| **Model** | | |\n", + "| n_basis | 7 | Number of Gaussian basis functions. |\n", + "| n_radial | 5 | Number of contracted basis functions. |\n", + "| nn | [512, 512] | Hidden layers and units. |\n", + "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", + "| r_min | 0.5 | Descriptor cutoff radius. |\n", + "| use_zbl | false | Use Zero-Body-Loss. |\n", + "| b_init | normal | Initialization scheme for biases. |\n", + "| descriptor_dtype | fp64 | Descriptor data type. |\n", + "| readout_dtype | fp32 | Readout data type. |\n", + "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", + "| **Loss** | | |\n", + "| loss_type | structures | Weighting scheme for atomic contributions. |\n", + "| name | energy | Quantity keyword. |\n", + "| weight | 1.0 | Weighting factor in loss function. |\n", + "| name | forces | Quantity keyword. |\n", + "| weight | 4.0 | Weighting factor in loss function. |\n", + "| **Metrics** | | |\n", + "| name | energy | Quantity keyword. |\n", + "| reductions | | List of reductions on target-prediction differences. |\n", + "| name | forces | Quantity keyword. |\n", + "| reductions | mae, mse | Reductions on target-prediction differences. |\n", + "| **Optimizer** | | |\n", + "| opt_name | adam | Optimizer name. |\n", + "| opt_kwargs | {} | Optimizer keyword arguments. |\n", + "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", + "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", + "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", + "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", + "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", + "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", + "| **Callbacks** | | |\n", + "| name | csv | Callback name. |\n", + "| **Progress Bar** | | |\n", + "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", + "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", + "| **Checkpoints** | | |\n", + "| ckpt_interval | 1 | Epochs between checkpoints. |\n", + "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", + "| reset_layers | [] | List of layers to reinitialize parameters. |\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -419,11 +562,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rm: cannot remove 'eval.log': No such file or directory\n" + ] + } + ], "source": [ - "# !rm -r project config.yaml error_config.yaml" + "!rm -r project config.yaml error_config.yaml eval.log" ] }, { From 216a5b6dd3446ce80013c8e392f7f5ff45965e9f Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 10:56:41 +0100 Subject: [PATCH 078/192] added config to documentation --- docs/source/_tutorials/05_Full_Config.nblink | 3 + docs/source/_tutorials/index.rst | 1 + examples/05_Full_Config.ipynb | 111 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 docs/source/_tutorials/05_Full_Config.nblink create mode 100644 examples/05_Full_Config.ipynb diff --git a/docs/source/_tutorials/05_Full_Config.nblink b/docs/source/_tutorials/05_Full_Config.nblink new file mode 100644 index 00000000..e191e9d6 --- /dev/null +++ b/docs/source/_tutorials/05_Full_Config.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/05_Full_Config.ipynb" +} diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index e91c16a4..fef7bdc3 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -8,3 +8,4 @@ Tutorials 02_Molecular_dynamics 03_Transfer_Learning 04_Batch_Data_Selection + 05_Full_Config \ No newline at end of file diff --git a/examples/05_Full_Config.ipynb b/examples/05_Full_Config.ipynb new file mode 100644 index 00000000..64135e3b --- /dev/null +++ b/examples/05_Full_Config.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Complete Configuration File\n", + " \n", + "```yaml\n", + "n_epochs: # Number of training epochs.\n", + "seed: 1 # Seed for initialising random numbers\n", + "patience: None # Number of epochs without improvement before trainings gets terminated.\n", + "n_models: 1 # Number of models to be trained at once.\n", + "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. \n", + " # Can yield singificant speedups for small structures or small batch sizes.\n", + "\n", + "data:\n", + " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", + " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", + " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", + " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", + " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", + " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", + "\n", + " n_train: 1000 # Number of training datapoints from `data_path`.\n", + " n_valid: 100 # Number of validation datapoints from `data_path`.\n", + "\n", + " batch_size: 32 # Number of training examples to be evaluated at once.\n", + " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", + "\n", + " shift_method: \"per_element_regression_shift\"\n", + " shift_options:\n", + " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", + " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", + "\n", + " pos_unit: Ang\n", + " energy_unit: eV\n", + "\n", + " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", + "\n", + "model:\n", + " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", + " n_radial: 5 # Number of contracted basis functions.\n", + " nn: [512, 512] # Number of hidden layers and units in those layers.\n", + "\n", + " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", + " r_min: 0.5 # Cutoff radius of the descriptor.\n", + "\n", + " use_zbl: false # \n", + "\n", + " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", + " descriptor_dtype: fp64\n", + " readout_dtype: fp32\n", + " scale_shift_dtype: fp32\n", + "\n", + "loss:\n", + "- loss_type: structures # Weighting scheme for atomic contributions.\n", + " # See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", + " name: energy # Keyword of the quantity e.g `energy`.\n", + " weight: 1.0 # Weighting factor in the overall loss function.\n", + "- loss_type: structures\n", + " name: forces\n", + " weight: 4.0\n", + "\n", + "metrics:\n", + "- name: energy # Keyword of the quantity e.g `energy`.\n", + " reductions: # List of reductions performed on the difference between target and predictions.\n", + " # Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", + " - mae\n", + "- name: forces\n", + " reductions:\n", + " - mae\n", + " - mse\n", + "\n", + "optimizer:\n", + " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", + " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", + " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", + " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", + " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", + " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", + " zbl_lr: 0.001 # \n", + " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", + "\n", + "callbacks:\n", + "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", + "\n", + "progress_bar:\n", + " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", + " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", + "\n", + "\n", + "checkpoints:\n", + " ckpt_interval: 1 # Number of epochs between checkpoints.\n", + " \n", + " # The options below are used for transfer learning\n", + " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", + " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", + "\n", + "```" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 5ed21d584094563c31c4dac1df7798503d7d702f Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 10:57:43 +0100 Subject: [PATCH 079/192] eval docu start --- examples/01_Model_Training.ipynb | 161 +++++++------------------------ 1 file changed, 36 insertions(+), 125 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 913956e9..9a8192c4 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -70,13 +70,6 @@ "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", " pid, fd = os.forkpty()\n" ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "There is already a config file in the working directory.\n" - ] } ], "source": [ @@ -243,6 +236,8 @@ "from ase.units import kcal, mol, Ang\n", "from ase.io import read, write\n", "from ase.calculators.singlepoint import SinglePointCalculator\n", + "\n", + "\n", "atoms = read(file_path, \":\")\n", "for atom in atoms:\n", " energy = atom.get_total_energy() * kcal/mol\n", @@ -254,41 +249,30 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12911.35it/s]\n" - ] - }, - { - "ename": "IndexError", - "evalue": "list index out of range", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 18\u001b[0m\n\u001b[1;32m 5\u001b[0m config_updates \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mn_epochs\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;241m100\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdata\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 13\u001b[0m }\n\u001b[1;32m 14\u001b[0m }\n\u001b[1;32m 16\u001b[0m config_dict \u001b[38;5;241m=\u001b[39m mod_config(config_path, config_updates)\n\u001b[0;32m---> 18\u001b[0m \u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig_dict\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/uni/dev/apax/apax/train/run.py:70\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(user_config, log_level)\u001b[0m\n\u001b[1;32m 68\u001b[0m train_raw_ds, val_raw_ds \u001b[38;5;241m=\u001b[39m load_data_files(config\u001b[38;5;241m.\u001b[39mdata)\n\u001b[1;32m 69\u001b[0m train_ds, ds_stats \u001b[38;5;241m=\u001b[39m initialize_dataset(config, train_raw_ds)\n\u001b[0;32m---> 70\u001b[0m val_ds \u001b[38;5;241m=\u001b[39m \u001b[43minitialize_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mval_raw_ds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcalc_stats\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 72\u001b[0m train_ds\u001b[38;5;241m.\u001b[39mset_batch_size(config\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39mbatch_size)\n\u001b[1;32m 73\u001b[0m val_ds\u001b[38;5;241m.\u001b[39mset_batch_size(config\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39mvalid_batch_size)\n", - "File \u001b[0;32m~/uni/dev/apax/apax/data/initialization.py:51\u001b[0m, in \u001b[0;36minitialize_dataset\u001b[0;34m(config, atoms_list, read_labels, calc_stats)\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m calc_stats \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m read_labels:\n\u001b[1;32m 48\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 49\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCannot calculate scale/shift parameters without reading labels.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 50\u001b[0m )\n\u001b[0;32m---> 51\u001b[0m inputs \u001b[38;5;241m=\u001b[39m \u001b[43mprocess_inputs\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 52\u001b[0m \u001b[43m \u001b[49m\u001b[43matoms_list\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 53\u001b[0m \u001b[43m \u001b[49m\u001b[43mr_max\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mr_max\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 54\u001b[0m \u001b[43m \u001b[49m\u001b[43mdisable_pbar\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprogress_bar\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdisable_nl_pbar\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 55\u001b[0m \u001b[43m \u001b[49m\u001b[43mpos_unit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpos_unit\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 56\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 57\u001b[0m labels \u001b[38;5;241m=\u001b[39m atoms_to_labels(\n\u001b[1;32m 58\u001b[0m atoms_list,\n\u001b[1;32m 59\u001b[0m additional_properties_info\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39madditional_properties_info,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 62\u001b[0m energy_unit\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mdata\u001b[38;5;241m.\u001b[39menergy_unit,\n\u001b[1;32m 63\u001b[0m )\n\u001b[1;32m 65\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m calc_stats:\n", - "File \u001b[0;32m~/uni/dev/apax/apax/data/input_pipeline.py:105\u001b[0m, in \u001b[0;36mprocess_inputs\u001b[0;34m(atoms_list, r_max, disable_pbar, pos_unit)\u001b[0m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mprocess_inputs\u001b[39m(\n\u001b[1;32m 100\u001b[0m atoms_list: \u001b[38;5;28mlist\u001b[39m,\n\u001b[1;32m 101\u001b[0m r_max: \u001b[38;5;28mfloat\u001b[39m,\n\u001b[1;32m 102\u001b[0m disable_pbar\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m 103\u001b[0m pos_unit: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAng\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 104\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mdict\u001b[39m:\n\u001b[0;32m--> 105\u001b[0m inputs \u001b[38;5;241m=\u001b[39m \u001b[43matoms_to_inputs\u001b[49m\u001b[43m(\u001b[49m\u001b[43matoms_list\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpos_unit\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 106\u001b[0m idx, offsets \u001b[38;5;241m=\u001b[39m dataset_neighborlist(\n\u001b[1;32m 107\u001b[0m inputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpositions\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[1;32m 108\u001b[0m box\u001b[38;5;241m=\u001b[39minputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfixed\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbox\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 111\u001b[0m disable_pbar\u001b[38;5;241m=\u001b[39mdisable_pbar,\n\u001b[1;32m 112\u001b[0m )\n\u001b[1;32m 114\u001b[0m inputs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124midx\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m idx\n", - "File \u001b[0;32m~/uni/dev/apax/apax/utils/convert.py:75\u001b[0m, in \u001b[0;36matoms_to_inputs\u001b[0;34m(atoms_list, pos_unit)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Converts an list of ASE atoms to a dict where all inputs\u001b[39;00m\n\u001b[1;32m 49\u001b[0m \u001b[38;5;124;03mare sorted by their shape (ragged/fixed). Units are\u001b[39;00m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;124;03madjusted if ASE compatible and provided in the inputpipeline.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[38;5;124;03m Labels are trainable system properties.\u001b[39;00m\n\u001b[1;32m 63\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 64\u001b[0m inputs \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 65\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mragged\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\n\u001b[1;32m 66\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpositions\u001b[39m\u001b[38;5;124m\"\u001b[39m: [],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 72\u001b[0m },\n\u001b[1;32m 73\u001b[0m }\n\u001b[0;32m---> 75\u001b[0m box \u001b[38;5;241m=\u001b[39m \u001b[43matoms_list\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241m.\u001b[39mcell\u001b[38;5;241m.\u001b[39marray\n\u001b[1;32m 76\u001b[0m pbc \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mall(box \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1e-6\u001b[39m)\n\u001b[1;32m 78\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m atoms \u001b[38;5;129;01min\u001b[39;00m atoms_list:\n", - "\u001b[0;31mIndexError\u001b[0m: list index out of range" + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11178.61it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11958.10it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:37<00:00, 2.18s/it, val_loss=0.31]\n" ] } ], "source": [ "from apax.train.run import run\n", + "from apax.utils.helpers import mod_config\n", + "\n", "\n", "config_path = Path(\"config.yaml\")\n", "\n", "config_updates = {\n", " \"n_epochs\": 100,\n", " \"data\": {\n", - " \"experiment\": \"benzene_dft_script2\",\n", + " \"experiment\": \"benzene_dft_script\",\n", " \"directory\": \"project/models\",\n", " \"data_path\": str(file_path),\n", " \"energy_unit\": \"kcal/mol\",\n", @@ -303,16 +287,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import csv\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "\n", - "path = \"project/models/benzene_dft_script2/log.csv\"\n", + "path = \"project/models/benzene_dft_script/log.csv\"\n", "\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", "data_dict = {}\n", @@ -363,13 +358,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 367.62it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 5.20it/s, test_loss=0.06859629925320611]\n" + ] + } + ], "source": [ "from apax.train.eval import eval_model\n", "\n", - "eval_model(config_dict, n_test=100)\n", + "eval_model(config_dict, n_test=10)\n", "# !apax eval config.yaml" ] }, @@ -387,100 +391,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## A Closer Look At Training Parameters\n", - "\n", - "```yaml\n", - "n_epochs: # Number of training epochs.\n", - "seed: 1 # Seed for initialising random numbers\n", - "patience: None # Number of epochs without improvement before trainings gets terminated.\n", - "n_models: 1 # Number of models to be trained at once.\n", - "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. \n", - " # Can yield singificant speedups for small structures or small batch sizes.\n", - "\n", - "data:\n", - " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", - " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", - " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", - " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", - " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", - " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", - "\n", - " n_train: 1000 # Number of training datapoints from `data_path`.\n", - " n_valid: 100 # Number of validation datapoints from `data_path`.\n", - "\n", - " batch_size: 32 # Number of training examples to be evaluated at once.\n", - " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", - "\n", - " shift_method: \"per_element_regression_shift\"\n", - " shift_options:\n", - " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", - " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", - "\n", - " pos_unit: Ang\n", - " energy_unit: eV\n", - "\n", - " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", - "\n", - "model:\n", - " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", - " n_radial: 5 # Number of contracted basis functions.\n", - " nn: [512, 512] # Number of hidden layers and units in those layers.\n", - "\n", - " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", - " r_min: 0.5 # Cutoff radius of the descriptor.\n", - "\n", - " use_zbl: false # \n", - "\n", - " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", - " descriptor_dtype: fp64\n", - " readout_dtype: fp32\n", - " scale_shift_dtype: fp32\n", - "\n", - "loss:\n", - "- loss_type: structures # Weighting scheme for atomic contributions.\n", - " # See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", - " name: energy # Keyword of the quantity e.g `energy`.\n", - " weight: 1.0 # Weighting factor in the overall loss function.\n", - "- loss_type: structures\n", - " name: forces\n", - " weight: 4.0\n", - "\n", - "metrics:\n", - "- name: energy # Keyword of the quantity e.g `energy`.\n", - " reductions: # List of reductions performed on the difference between target and predictions.\n", - " # Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", - " - mae\n", - "- name: forces\n", - " reductions:\n", - " - mae\n", - " - mse\n", - "\n", - "optimizer:\n", - " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", - " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", - " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", - " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", - " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", - " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", - " zbl_lr: 0.001 # \n", - " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", - "\n", - "callbacks:\n", - "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", - "\n", - "progress_bar:\n", - " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", - " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", - "\n", - "\n", - "checkpoints:\n", - " ckpt_interval: 1 # Number of epochs between checkpoints.\n", - " \n", - " # The options below are used for transfer learning\n", - " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", - " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", - "\n", - "```" + "## A Closer Look At Training Parameters" ] }, { From 032363816e902d9684beafdc8965e6d46b8642a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:10:38 +0000 Subject: [PATCH 080/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/_tutorials/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index fef7bdc3..688967c5 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -8,4 +8,4 @@ Tutorials 02_Molecular_dynamics 03_Transfer_Learning 04_Batch_Data_Selection - 05_Full_Config \ No newline at end of file + 05_Full_Config From eaf5a0409a9638ac812adc1a9127d91afda19f6c Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 11:41:37 +0100 Subject: [PATCH 081/192] cleanup --- examples/01_Model_Training.ipynb | 222 ++++++++++++++++--------------- 1 file changed, 118 insertions(+), 104 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 2c278920..ad842eea 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -42,22 +42,6 @@ "For more information on the CLI, simply run `apax -h`." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!apax -h" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following command create a minimal configuration file in the working directory." - ] - }, { "cell_type": "code", "execution_count": 2, @@ -70,33 +54,57 @@ "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", " pid, fd = os.forkpty()\n" ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\u001b[1;33mUsage: \u001b[0m\u001b[1mapax [OPTIONS] COMMAND [ARGS]...\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m\n", + "\u001b[1m \u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Options \u001b[0m\u001b[2m───────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-version\u001b[0m \u001b[1;32m-V\u001b[0m \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-install\u001b[0m\u001b[1;36m-completion\u001b[0m Install completion for the current shell. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-show\u001b[0m\u001b[1;36m-completion\u001b[0m Show completion for the current shell, to \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m copy it or customize the installation. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m-\u001b[0m\u001b[1;36m-help\u001b[0m \u001b[1;32m-h\u001b[0m Show this message and exit. \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\u001b[2m╭─\u001b[0m\u001b[2m Commands \u001b[0m\u001b[2m──────────────────────────────────────────────────────────────────\u001b[0m\u001b[2m─╮\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mdocs \u001b[0m\u001b[1;36m \u001b[0m Opens the documentation website in your browser. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36meval \u001b[0m\u001b[1;36m \u001b[0m Starts performing the evaluation of the test dataset with \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvalidate \u001b[0m\u001b[1;36m \u001b[0m Validate training or MD config files. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mvisualize\u001b[0m\u001b[1;36m \u001b[0m Visualize a model based on a configuration file. A CO molecule is \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m taken as sample input (influences number of atoms, number of \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m species is set to 10). \u001b[2m│\u001b[0m\n", + "\u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n", + "\n" + ] } ], "source": [ - "!apax template train" + "!apax -h" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", - "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Further, the units of the labels have to be specified. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", - "\n", - "The filled in configuration file should look similar to this one.\n", - "\n", - "```yaml\n", - "epoch: 1000\n", - "data:\n", - " data_path: md17.extexyz\n", - " epochs: 1000\n", - " n_train: 1000\n", - " energy_unit: kcal/mol\n", - " pos_unit: Ang\n", - " ....\n", - "```\n", - "\n", - "It also can be modefied with the utils function `mod_config` provided by Apax.\n" + "The following command create a minimal configuration file in the working directory." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "!apax template train" ] }, { @@ -124,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -160,9 +168,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "config.yaml is a valid training config.\n" + ] + } + ], "source": [ "!apax validate train config.yaml" ] @@ -177,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -192,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -222,9 +239,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 11:21:13 | Initializing Callbacks\n", + "INFO | 11:21:13 | Initializing Loss Function\n", + "INFO | 11:21:13 | Initializing Metrics\n", + "INFO | 11:21:13 | Running Input Pipeline\n", + "INFO | 11:21:13 | Read data file project/benzene_mod.xyz\n", + "INFO | 11:21:13 | Loading data from project/benzene_mod.xyz\n", + "INFO | 11:21:24 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12020.13it/s]\n", + "INFO | 11:21:24 | Computing per element energy regression.\n", + "INFO | 11:21:31 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12084.55it/s]\n", + "INFO | 11:21:32 | Initializing Model\n", + "INFO | 11:21:32 | initializing 1 models\n", + "INFO | 11:21:38 | Initializing Optimizer\n", + "INFO | 11:21:38 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" + ] + } + ], "source": [ "!apax train config.yaml" ] @@ -252,36 +292,16 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from ase.units import kcal, mol, Ang\n", - "from ase.io import read, write\n", - "from ase.calculators.singlepoint import SinglePointCalculator\n", - "\n", - "\n", - "atoms = read(file_path, \":\")\n", - "for atom in atoms:\n", - " energy = atom.get_total_energy() * kcal/mol\n", - " forces = atom.get_forces() * kcal/mol/Ang\n", - " calc = SinglePointCalculator(atoms, energy=energy, forces=forces)\n", - " atom.calc = calc\n", - "write(file_path, atoms) " - ] - }, - { - "cell_type": "code", - "execution_count": 4, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11178.61it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11958.10it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:37<00:00, 2.18s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9622.30it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10820.94it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:35<00:00, 2.15s/it, val_loss=0.31]\n" ] } ], @@ -310,7 +330,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -381,23 +401,48 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 367.62it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 5.20it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 407.03it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 7.14it/s, test_loss=0.06859629925320611]\n" ] } ], "source": [ "from apax.train.eval import eval_model\n", "\n", - "eval_model(config_dict, n_test=10)\n", - "# !apax eval config.yaml" + "eval_model(config_dict, n_test=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5912.47it/s]\n", + "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.50it/s, test_loss=0.5443810628577777]\n" + ] + } + ], + "source": [ + "!apax eval config.yaml --n-data 10" ] }, { @@ -496,42 +541,11 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "rm: cannot remove 'eval.log': No such file or directory\n" - ] - } - ], - "source": [ - "!rm -r project config.yaml error_config.yaml eval.log" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To remove all the created files and clean up yor working directory run" - ] - }, - { - "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "!rm -r project config.yaml error_config.yaml" + "!rm -r project config.yaml error_config.yaml eval.log" ] } ], From 502361756476309783a4248c3d396cc981140d24 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:41:51 +0000 Subject: [PATCH 082/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/datasets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 48b97d8f..3819a12c 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -2,6 +2,7 @@ import urllib import zipfile + def download_md22_stachyose(data_path): url = "http://www.quantum-machine.org/gdml/repo/static/md22_stachyose.zip" file_path = data_path / "md22_stachyose.zip" From b8bfb32a56cb0a8abde658f005e573e9d4193deb Mon Sep 17 00:00:00 2001 From: Nico Segreto Date: Tue, 5 Mar 2024 11:49:19 +0100 Subject: [PATCH 083/192] Moredocs nico (#237) * mod_config bug fix * Metrics plot clean up * added config to documentation * eval documentation --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- apax/utils/datasets.py | 6 +- docs/source/_tutorials/05_Full_Config.nblink | 3 + docs/source/_tutorials/index.rst | 1 + examples/01_Model_Training.ipynb | 207 ++++++++++++------- examples/05_Full_Config.ipynb | 111 ++++++++++ 5 files changed, 248 insertions(+), 80 deletions(-) create mode 100644 docs/source/_tutorials/05_Full_Config.nblink create mode 100644 examples/05_Full_Config.ipynb diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index b6935037..3819a12c 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -20,7 +20,7 @@ def download_md22_stachyose(data_path): return file_path -def download_md17_benzene_DFT(data_path): +def download_benzene_DFT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip" file_path = data_path / "benzene2018_dft.zip" @@ -36,7 +36,7 @@ def download_md17_benzene_DFT(data_path): return new_file_path -def download_md17_benzene_CCSDT(data_path): +def download_md22_benzene_CCSDT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene_ccsd_t.zip" file_path = data_path / "benzene_ccsdt.zip" @@ -63,7 +63,7 @@ def modify_xyz_file(file_path, target_string, replacement_string): return new_file_path -def mod_md17(file_path): +def mod_md_datasets(file_path): new_file_path = file_path.with_name(file_path.stem + "_mod" + file_path.suffix) with open(file_path, "r") as input_file, open(new_file_path, "w") as output_file: for line in input_file: diff --git a/docs/source/_tutorials/05_Full_Config.nblink b/docs/source/_tutorials/05_Full_Config.nblink new file mode 100644 index 00000000..e191e9d6 --- /dev/null +++ b/docs/source/_tutorials/05_Full_Config.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/05_Full_Config.ipynb" +} diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index e91c16a4..688967c5 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -8,3 +8,4 @@ Tutorials 02_Molecular_dynamics 03_Transfer_Learning 04_Batch_Data_Selection + 05_Full_Config diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 46f0c786..ad842eea 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -11,7 +11,7 @@ "\n", "## Acquiring a dataset\n", "\n", - "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/benzene2018_dft.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mop_md17` function in order to be readable." + "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://sgdml.org/?datasetID=benzene2018_dft). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mod_md_datasets` function in order to be readable." ] }, { @@ -21,12 +21,12 @@ "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_md17_benzene_DFT, mod_md17\n", + "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets, download_md22_benzene_CCSDT\n", "\n", "data_path = Path(\"project\")\n", "\n", - "file_path = download_md17_benzene_DFT(data_path)\n", - "file_path = mod_md17(file_path)" + "file_path = download_benzene_DFT(data_path)\n", + "file_path = mod_md_datasets(file_path)" ] }, { @@ -246,22 +246,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "INFO | 21:56:40 | Initializing Callbacks\n", - "INFO | 21:56:40 | Initializing Loss Function\n", - "INFO | 21:56:40 | Initializing Metrics\n", - "INFO | 21:56:40 | Running Input Pipeline\n", - "INFO | 21:56:40 | Read data file project/benzene_mod.xyz\n", - "INFO | 21:56:40 | Loading data from project/benzene_mod.xyz\n", - "INFO | 21:56:50 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 13135.40it/s]\n", - "INFO | 21:56:50 | Computing per element energy regression.\n", - "INFO | 21:56:57 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12868.33it/s]\n", - "INFO | 21:56:57 | Initializing Model\n", - "INFO | 21:56:58 | initializing 1 models\n", - "INFO | 21:57:04 | Initializing Optimizer\n", - "INFO | 21:57:04 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" + "INFO | 11:21:13 | Initializing Callbacks\n", + "INFO | 11:21:13 | Initializing Loss Function\n", + "INFO | 11:21:13 | Initializing Metrics\n", + "INFO | 11:21:13 | Running Input Pipeline\n", + "INFO | 11:21:13 | Read data file project/benzene_mod.xyz\n", + "INFO | 11:21:13 | Loading data from project/benzene_mod.xyz\n", + "INFO | 11:21:24 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12020.13it/s]\n", + "INFO | 11:21:24 | Computing per element energy regression.\n", + "INFO | 11:21:31 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12084.55it/s]\n", + "INFO | 11:21:32 | Initializing Model\n", + "INFO | 11:21:32 | initializing 1 models\n", + "INFO | 11:21:38 | Initializing Optimizer\n", + "INFO | 11:21:38 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" ] } ], @@ -287,7 +287,7 @@ "\n", "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint.\n", "\n", - "Furthermore, an Apax trianing can easily be started within a scriped." + "Furthermore, an Apax trianing can easily be started within a script." ] }, { @@ -299,14 +299,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 10410.16it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11413.38it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:43<00:00, 2.24s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9622.30it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10820.94it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:35<00:00, 2.15s/it, val_loss=0.31]\n" ] } ], "source": [ "from apax.train.run import run\n", + "from apax.utils.helpers import mod_config\n", + "\n", "\n", "config_path = Path(\"config.yaml\")\n", "\n", @@ -333,39 +335,9 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABa0AAAFzCAYAAAA9uyXqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACAc0lEQVR4nOzdd3hUddrG8XtKZtITUoEUeu9FkCKugn3t61qw4qq7omJX1sWy6uLqWtby2su69t4bIqJIkd57JxDSSE+mnvePSUaytCQkOZPh+7muXMCZM2eecBB/3PPM87MYhmEIAAAAAAAAAIAQYDW7AAAAAAAAAAAAahFaAwAAAAAAAABCBqE1AAAAAAAAACBkEFoDAAAAAAAAAEIGoTUAAAAAAAAAIGQQWgMAAAAAAAAAQgahNQAAAAAAAAAgZBBaAwAAAAAAAABCht3sAg6H3+/Xzp07FRcXJ4vFYnY5AAAAaCKGYaisrEzt27eX1UqfxZGENT4AAEB4asgav1WH1jt37lRWVpbZZQAAAKCZbN++XZmZmWaXgRbEGh8AACC81WeN36pD67i4OEmBbzQ+Pt7kagAAANBUSktLlZWVFVzv4cjBGh8AACA8NWSN36pD69qPC8bHx7OgBQAACEOMhzjysMYHAAAIb/VZ4zMgEAAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAyCK0BAAAAAAAAACGD0BoAAAAAAAAAEDIIrQEAAAAAAAAAIYPQGgAAAAAAAAAQMgitAQAAAAAAAAAhg9AaAAAAAAAAABAy7GYXAAAAgMOXU1ylDXnlymoTpeykaNlt9CYAAAAAaJ0IrQEAABpp9sYCfbdyty4b2VGdUmIOem61x6c35m7V5oIKxUVGKD7KHvgx0q74yAj1z0xQcqyzQa9f7vLq6+W79NGiHM3ZVBg8brda1CE5Wp1TY9U5NUadU2LUMTlGHVNilBbnlMViOeS1DcNQaZVXOcVV2llcpZ0lVeqaFquRXVIaVCMAAAAANBShNQAAaPUq3V7d8+lKLd1RrCm/761juqU2+lqGYdQr1P1g4Q7d8eEy+fyG3vp1myaN7aarjuksh33fDufZGwp01ycrtLmg4oDXc9itOntghv50TCd1S4874Hlur19zNhXqo0U79O3KXFV7/MHHOqXEaFdJlao9fm3Mr9DG/H1fLzLCqg5JMeqQHK3YSLu8PkMen18enyGv3y+316/8Mpd2Flepwu2r89yLhmcTWgMAAABodhbDMAyzi2is0tJSJSQkqKSkRPHx8WaXAwAATLC1sELX/Heh1uSWBY/9aXQn3XZyDznttgZda/rq3brl/aUanN1G953RR1lJ0fucYxiGnv9pkx76eo0kKSMxSjnFVZKkHulxmnpuPw3ObiNJKix36cGvVuujRTmSpLQ4p/4wJFPVHr/Kqj0qrfaorNqr3aXVdQLmY7un6k/HdNLorikyDGnVrlL9sqFAszcW6tfNRary/BYmd06N0TmDMnTWoAxltomW329oV2m1NuWXa1N+hTbml2tzQYW2FVVqx54q+fwNW/olxzjULjFS7ROidGyPVI0f3qFBz28s1nlHLu49AABAeGrIOo/QGgAABFW4vHr7123ql5GgYZ2S6tVxbKYf1+bphrcXq7Taq5RYp47plqKPFwcC4l7t4vXkBQMP2rW8tx/W7Naf/7tIbl+gczkywqpJY7vrT8d0UkTNfGi/39ADX67WK79sliRdPaaz7jy5pz5bulN//2KViircslikS47uoN7t4vXPb9ZoT6UneOzWk3ooPjJiv6+/cGuRXvp5s75dmavaXLlzSoyKKt0qrvTUOTc5xqHT+rfTOYMzNSAzod73yePzK2dPlbYUVmhrYaWqPD5F2KyKsFkUYbPKbrXIYbcqOcap9omRap8YpciIhgX/TYV13pGLew8AABCeCK0BAECD+f2Grv7vQn2/erckaVB2ov58bBed0CtdVmtohdeGYej/ftyof323VoYhDcxK1HMXD1HbhEhNW7Vbd3y4TEUVbjntVv3t97118fDsgwa7M9bm6ZrXF8rt8+vE3ukqq/YGZ0T3SI/TP87pq34Zibr1/aX6bOlOSdJdp/bSVWM6B6+xp8KtB79arQ8W7qhz7Z5t4zT1nH4aVNN9fSjbCiv1yi+b9d6C7aqsGc8R67RreKckjeiSrFFdU9QjPS7k7klTY5135OLeAwAAhCdCawAA0GCPTVunJ6evl8NmlSyB2clSYPzENWM666xBGQ0et9EQhmFoa2Gllmwv1pLtxVq8bY/W7i5TYpQj2PWbkRiljDZRmr2hUN+szJUkXTgsS/ee0adObXml1brl/aX6eX2BJGlM91RNGttVQzok7fO6M9fl66rXF8jt9euUvm315IWD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Hdg2q0VtogmtAQAAED4ef/xxjR8/XpGRkQcdIVjfsYGhssbf22+d1l6TKwEAADgyNSq0nj59us444wx17txZa9asUd++fbVlyxYZhqHBgwfX+zqGYej666/Xxx9/rB9//FGdOnVqTDktLj7SLofNKrfPr4JylzLbRNd5vHYTxuQYh6xWixklAgAAAM1i77GBzT1C0Cy/bcR4+DO7AQAA0HDWxjxp8uTJuvXWW7V8+XJFRkbqww8/1Pbt23XsscfqvPPOq/d1Jk6cqDfeeENvvfWW4uLilJubq9zcXFVVVTWmrBZjsViCYz/2N9eaTRgBAACA1qt2PEiVh05rAAAAMzSq03r16tV6++23Axew21VVVaXY2Fj9/e9/15lnnqm//OUv9brOs88+K0n63e9+V+f4q6++qssvv7wxpbWYlDindpZU73eudW2nNZswAgAAINw15djAUMFGjAAAAOZqVGgdExMTXJC2a9dOGzduVJ8+fSRJBQUF9b6OYRiNefmQUBtI55fvJ7Sm0xoAAABHgKYaGxhqfhsPQmgNAABghkaNBzn66KM1a9YsSdKpp56qW265RQ8++KAmTJigo48+ukkLDFWpNaH1/jqta8eD0GkNAACAcNZUYwNDTVRwPAihNQAAgBka1Wn92GOPqby8XJJ03333qby8XO+++666devWaj8C2FApcbUzrQ82HsTRojUBAAAALampxgaGmmg6rQEAAEzVqND6H//4hy6++GJJgVEhzz33XJMW1RrUdlGzESMAAACOVE01NjDUREYw0xoAAMBMjRoPkp+fr5NPPllZWVm67bbbtHTp0qauK+QddKZ1Tad1KuNBAAAAEMbCdWxgtCPQ21PNeBAAAABTNCq0/vTTT7Vr1y5NmTJF8+fP1+DBg9WnTx/94x//0JYtW5q4xND0W6f1/mZaB7pN6LQGAABAOHvsscc0fPhwSYGxgWPHjtW7776rjh076uWXXza5usarHQ9CpzUAAIA5GjUeRJLatGmjq6++WldffbV27Niht99+W6+88oruvvtueb3epqwxJKXWzrT+n40YXV6fSqo8ktiIEQAAAOHL5/Npx44d6t+/v6TwGhsYyUaMAAAApmpUp/XePB6PFixYoHnz5mnLli1KT09virpCXm0gXVrtlcv722K2sKbLOsJmUUJUhCm1AQAAAM3NZrPpxBNP1J49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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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YjgAAIAVIiqGf/DBB83ab/v27crOzj7i2eItbfLkycrLywv9XFpaqpycHAsjAgAAAHAkYinHd9rrG4ZYRBMAAMA6ERXDm2vQoEHKz89Xnz59onK8rKwsFRUVhW0rKipSSkqKEhMTZbfbZbfbm9wnKyvrkMd1u91yu91RiREAAACA9WIpxzcMQy67TR6fn0U0AQAALNSiLdumGd3FYcaMGaOlS5eGbVuyZInGjBkjSXK5XBo5cmTYPn6/X0uXLg3tAwAAAKDtKS4ubrTtT3/6U6MRibEqODecznAAAADrWDq/pLy8XPn5+crPz5ckFRQUKD8/X1u3bpUU+GjjhAkTQvv/+te/1nfffae7775b69at0x//+Ee98soruv3220P75OXl6fnnn9e8efP07bff6vrrr1dFRYUmTZrUqo8NAAAAQGSmT5+uhQsXhn6++OKL1blzZ3Xv3l2rV68Obb/88svVoUMHK0I8bMFiuJfOcAAAAMtYWgz//PPPNWLEiNBinHl5eRoxYoSmTp0qSdq1a1eoMC5JvXv31ptvvqklS5Zo2LBheuKJJ/TCCy9o7NixoX0uueQS/eEPf9DUqVM1fPhw5efna/HixW2mYwQAAABo72bPnh2a771kyRItWbJEb7/9tsaNG6e77rrL4ugiE1xEk85wAAAA67TozPAfc9ppp/3gKJW5c+c2eZsvv/zyB49700036aabbjrS8AAAAABYoLCwMFQMf+ONN3TxxRfrrLPOUq9evTR69GiLo4tMsDO8hmI4AACAZVq0M9wwjB/fCQAAAAAa6NSpk7Zt2yZJWrx4sXJzcyUF1iTy+XxWhhYxpz3w2ojOcAAAAOu0aGd4tBfQBAAAABD/fv7zn+vyyy9X//79tW/fPo0bN06S9OWXX6pfv34WRxcZl8MuSfIwMxwAAMAyUSmGl5aW6v3339eAAQN09NFHh7avXbtW2dnZ0bgLAAAAAO3Ek08+qV69emnbtm16/PHH1bFjR0mBNYVuuOEGi6OLTHBMCp3hAAAA1omoGH7xxRfrpz/9qW666SZVVVVp1KhR2rJli0zT1IIFC/SLX/xCkkJz/gAAAACguZxOp+68885G22+//XYLookOd90Cml46wwEAACwT0czwDz/8UKeccook6Z///KdM01RxcbGefvppPfLII1ENEAAAAED789e//lUnn3yysrOz9f3330uSZs6cqddff93iyCJDZzgAAID1IiqGl5SUKD09XVJgQZtf/OIXSkpK0rnnnquNGzdGNUAAAAAA7ctzzz2nvLw8jRs3TsXFxaFFM9PS0jRz5kxrg4sQxXAAAADrRVQMz8nJ0YoVK1RRUaHFixfrrLPOkiQdOHBACQkJUQ0QAAAAQPvyzDPP6Pnnn9d9990nu90e2j5q1CitWbPGwsgi57QbkqQaxqQAAABYJqKZ4bfddpvGjx+vjh07qkePHjrttNMkBcanDBkyJJrxAQAAAGhnCgoKNGLEiEbb3W63KioqLIjoyLkcgaI+neEAAADWiagYfsMNN+j444/Xtm3bdOaZZ8pmCzSY9+nTh5nhAAAAAI5I7969lZ+fr549e4ZtX7x4sY4++miLojoyLjtjUgAAAKwWUTFcCnxEcejQoSooKFDfvn3lcDh07rnnRjM2AAAAAO1QXl6ebrzxRlVXV8s0TX366aeaP3++pk2bphdeeMHq8CISnBnuZUwKAACAZSIqhldWVurmm2/WvHnzJEkbNmxQnz59dPPNN6t79+665557ohokAAAAgPbjmmuuUWJion7729+qsrJSl19+ubKzs/XUU0/p0ksvtTq8iLhZQBMAAMByES2gOXnyZK1evVrLli0LWzAzNzdXCxcujFpwAAAAANqn8ePHa+PGjSovL1dhYaG2b9+uX/3qV1aHFbFgZ7iHznAAAADLRNQZvmjRIi1cuFAnnHCCDMMIbR88eLA2b94cteAAAAAAtD8FBQWqra1V//79lZSUpKSkJEnSxo0b5XQ61atXL2sDjAAzwwEAAKwXUWf4nj171LVr10bbKyoqworjAAAAAHC4rrrqKn388ceNtq9cuVJXXXVV6wcUBc66YngNxXAAAADLRFQMHzVqlN58883Qz8EC+AsvvKAxY8ZEJzIAAAAA7dKXX36pk046qdH2E044Qfn5+a0fUBS4mBkOAABguYjGpDz66KMaN26c1q5dq9raWj311FNau3atPv74Yy1fvjzaMQIAAABoRwzDUFlZWaPtJSUl8vl8FkR05JgZDgAAYL2IOsNPPvlk5efnq7a2VkOGDNG7776rrl27asWKFRo5cmS0YwQAAADQjvz0pz/VtGnTwgrfPp9P06ZN08knn2xhZJELFsO9dIYDAABYJqLOcEnq27evnn/++WjGAgAAAAB67LHHdOqpp2rAgAE65ZRTJEn/+c9/VFpaqvfff9/i6CLjttMZDgAAYLWIOsPfeustvfPOO422v/POO3r77bePOCgAAAAA7dfgwYP11Vdf6eKLL9bu3btVVlamCRMmaN26dTrmmGOsDi8izAwHAACwXkSd4ffcc48ee+yxRttN09Q999yjcePGHXFgAAAAANofr9ers88+W7Nnz9ajjz5qdThR47RTDAcAALBaRJ3hGzdu1KBBgxptHzhwoDZt2nTEQQEAAABon5xOp7766iurw4i6YGd4DWNSAAAALBNRMTw1NVXfffddo+2bNm1Shw4djjgoAAAAAO3XFVdcoRdffNHqMKKKMSkAAADWi2hMygUXXKDbbrtN//znP9W3b19JgUL4HXfcofPPPz+qAQIAAABoX2prazVnzhy99957GjlyZKOGmxkzZlgUWeRcdWNSvHSGAwAAWCaiYvjjjz+us88+WwMHDtRRRx0lSdq+fbtOOeUU/eEPf4hqgAAAAADal6+//lrHHnusJGnDhg1h1xmGYUVIR4zOcAAAAOtFVAxPTU3Vxx9/rCVLlmj16tVKTEzU0KFD9dOf/jTa8QEAAABoZz744AOrQ4g6N8VwAAAAyx12Mdzr9SoxMVH5+fk666yzdNZZZ7VEXAAAAACg7du3S1LoE6ltlbNuTIqHMSkAAACWOewFNJ1Op3r06CGfz9cS8QAAAABo5/x+vx566CGlpqaqZ8+e6tmzp9LS0vTwww/L72+bxWTGpAAAAFjvsIvhknTffffp3nvv1f79+6MdDwAAAIB27r777tOzzz6rxx57TF9++aW+/PJLPfroo3rmmWc0ZcoUq8OLCMVwAAAA60U0M/zZZ5/Vpk2blJ2drZ49ezZa3f2LL76ISnAAAAAA2p958+bphRde0Pnnnx/aNnToUHXv3l033HCDfve731kYXWRcDcakmKbZZhcCBQAAaMsiKoZfeOGFUQ4DAAAAAAL279+vgQMHNto+cODANvvp1GBnuCR5faZcDorhAAAArS2iYvj9998f1SBmzZql3//+9yosLNSwYcP0zDPP6Pjjj29y39NOO03Lly9vtP2cc87Rm2++KUm66qqrNG/evLDrx44dq8WLF0c1bgAAAADRN2zYMD377LN6+umnw7Y/++yzGjZsmEVRHRl3g2K4x+cPK44DAACgdURUDA9atWqVvv32W0nS4MGDNWLEiMM+xsKFC5WXl6fZs2dr9OjRmjlzpsaOHav169era9eujfb/xz/+IY/HE/p53759GjZsmC666KKw/c4++2z95S9/Cf3sdrsPOzYAAAAAre/xxx/Xueeeq/fee09jxoyRJK1YsULbtm3TW2+9ZXF0kXHaGxTDa/0SL08AAABaXUTF8N27d+vSSy/VsmXLlJaWJkkqLi7W6aefrgULFqhLly7NPtaMGTN07bXXatKkSZKk2bNn680339ScOXN0zz33NNo/PT097OcFCxYoKSmpUTHc7XYrKyvrMB8ZAAAAAKudeuqp2rBhg2bNmqV169ZJkn7+85/rhhtuUHZ2tsXRRcZuM2S3GfL5TRbRBAAAsEhEn827+eabVVZWpm+++Ub79+/X/v379fXXX6u0tFS33HJLs4/j8Xi0atUq5ebm1gdksyk3N1crVqxo1jFefPFFXXrppY0W8Vy2bJm6du2qAQMG6Prrr9e+ffsOeYyamhqVlpaGXQAAAAC0np///OehPPyll15S586d9bvf/U6vvfaaXnvtNT3yyCOHVQiPxRw/tIgmxXAAAABLRFQMX7x4sf74xz/q6KOPDm0bNGiQZs2apbfffrvZx9m7d698Pp8yMzPDtmdmZqqwsPBHb//pp5/q66+/1jXXXBO2/eyzz9ZLL72kpUuXavr06Vq+fLnGjRsnn8/X5HGmTZum1NTU0CUnJ6fZjwEAAADAkXvjjTdUUVEhSZo0aZJKSkqO6HixmOMH54R7fBTDAQAArBDRmBS/3y+n09lou9PplN/feondiy++qCFDhjRabPPSSy8NfT9kyBANHTpUffv21bJly3TGGWc0Os7kyZOVl5cX+rm0tDQmkmUAAACgvRg4cKAmT56s008/XaZp6pVXXlFKSkqT+06YMOFHjxeLOX6oGE5nOAAAgCUiKob/z//8j2699VbNnz8/9FHFHTt26Pbbb2+y2HwoGRkZstvtKioqCtteVFT0o/O+KyoqtGDBAj300EM/ej99+vRRRkaGNm3a1GR8brebBTYBAAAAC82ePVt5eXl68803ZRiGfvvb38owjEb7GYbRrGJ4LOb4oTEpdIYDAABYIqIxKc8++6xKS0vVq1cv9e3bV3379lXv3r1VWlqqZ555ptnHcblcGjlypJYuXRra5vf7tXTp0tCq8Yfy6quvqqamRldcccWP3s/27du1b98+devWrdmxAQAAAGg9J554oj755BPt2bNHpmlqw4YNOnDgQKPL/v37rQ41YnSGAwAAWCuizvCcnBx98cUXeu+990Krux999NFhC2E2V15eniZOnKhRo0bp+OOP18yZM1VRUaFJkyZJCnwEsnv37po2bVrY7V588UVdeOGF6ty5c9j28vJyPfjgg/rFL36hrKwsbd68WXfffbf69eunsWPHRvJwAQAAALSigoICdenS5Uf3u+GGG/TQQw8pIyOjFaI6ciygCQAAYK1mF8PT09O1YcMGZWRk6Oqrr9ZTTz2lM888U2eeeeYRBXDJJZdoz549mjp1qgoLCzV8+HAtXrw4tKjm1q1bZbOFN7CvX79eH330kd59991Gx7Pb7frqq680b948FRcXKzs7W2eddZYefvjhmPuYJAAAAIDGevbs2az9/va3v+nOO+9sO8Xw0AKaPosjAQAAaJ+aXQz3eDwqLS1VRkaG5s2bp+nTpys5OTkqQdx000266aabmrxu2bJljbYNGDBApmk2uX9iYqLeeeedqMQFAAAAIHYd6jVBrGJMCgAAgLWaXQwfM2aMLrzwQo0cOVKmaeqWW25RYmJik/vOmTMnagG2BwcqPLr0z5+ovKZWH/3m9CYXCgIAAADQttUvoNm2ivgAAADxotnF8L/97W968skntXnzZhmGoZKSElVXV7dkbO1Gosuu9UVlkqTymlolJzgtjggAAABAtNEZDgAAYK1mF8MzMzP12GOPSZJ69+6tv/71r40Wr0RkEpx2uRw2eWr9KqnyUgwHAAAA4pCTBTQBAAAsZfvxXRorKChoViF8yJAh2rZtWyR30e6kJgYK4MWVXosjAQAAANAS3KHOcBbQBAAAsEJExfDm2rJli7xeirvNkVZXDC+t4vkCAAAAmuOKK65QSkqK1WE0W2hMio/OcAAAACs0e0wKWlawM7yEYjgAAACg4uJiffrpp9q9e7f8/vDi8YQJEyRJzz33nBWhRczFmBQAAABLUQyPERTDAQAAgIB///vfGj9+vMrLy5WSkiLDMELXGYYRKoa3NfWd4abFkQAAALRPLTomBc1HMRwAAAAIuOOOO3T11VervLxcxcXFOnDgQOiyf/9+q8OLWKgYTmc4AACAJSiGx4iU4AKaFMMBAADQzu3YsUO33HKLkpKSrA4lqiiGAwAA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3W7169dPL774Ytg+q1at0qhRo5SUlKQTTzxR69evb9kHDgAAAMQpcnwAaFkUwwGgjZo2bZpeeuklzZ49W998841uv/12XXHFFVq+fHlon7vuuktPPPGEPvvsM3Xp0kXnnXeevF6vpECCe/HFF+vSSy/VmjVr9MADD2jKlCmaO3du6PYTJkzQ/Pnz9fTTT+vbb7/Vn/70J3Xs2DEsjvvuu09PPPGEPv/8czkcDl199dWt8vgBAACAeEOODwAtyzBN07Q6CADA4ampqVF6erree+89jRkzJrT9mmuuUWVlpa677jqdfvrpWrBggS655BJJ0v79+3XUUUdp7ty5uvjiizV+/Hjt2bNH7777buj2d999t958801988032rBhgwYMGKAlS5YoNze3UQzLli3T6aefrvfee09nnHGGJOmtt97Sueeeq6qqKiUkJLTwswAAAADED3J8AGh5dIYDQBu0adMmVVZW6swzz1THjh1Dl5deekmbN28O7dcwiU5PT9eAAQP07bffSpK+/fZbnXTSSWHHPemkk7Rx40b5fD7l5+fLbrfr1FNP/cFYhg4dGvq+W7dukqTdu3cf8WMEAAAA2hNyfABoeQ6rAwAAHL7y8nJJ0ptvvqnu3buHXed2u8OS5UglJiY2az+n0xn63jAMSYFZhwAAAACajxwfAFoeneEA0AYNGjRIbrdbW7duVb9+/cIuOTk5of0++eST0PcHDhzQhg0bdPTRR0uSjj76aP33v/8NO+5///tf/eQnP5HdbteQIUPk9/vD5hMCAAAAaBnk+ADQ8ugMB4A2KDk5WXfeeaduv/12+f1+nXzyySopKdF///tfpaSkqGfPnpKkhx56SJ07d1ZmZqbuu+8+ZWRk6MILL5Qk3XHHHTruuOP08MMP65JLLtGKFSv07LPP6o9//KMkqVevXpo4caKuvvpqPf300xo2bJi+//577d69WxdffLFVDx0AAACIS+T4ANDyKIYDQBv18MMPq0uXLpo2bZq+++47paWl6dhjj9W9994b+gjjY489pltvvVUbN27U8OHD9e9//1sul0uSdOyxx+qVV17R1KlT9fDDD6tbt2566KGHdNVVV4Xu47nnntO9996rG264Qfv27VOPHj107733WvFwAQAAgLhHjg8ALcswTdO0OggAQHQFV4E/cOCA0tLSrA4HAAAAwBEixweAI8fMcAAAAAAAAABA3KMYDgAAAAAAAACIe4xJAQAAAAAAAADEPTrDAQAAAAAAAABxj2I4AAAAAAAAACDuUQwHAAAAAAAAAMQ9iuEAAAAAAAAAgLhHMRwAAAAAAAAAEPcohgMAAAAAAAAA4h7FcAAAAAAAAABA3KMYDgAAAAAAAACIexTDAQAAAAAAAABx7/8DsOZs+jewUbAAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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BgAAAIDDEFnR7QuZXAkAAEDXRdANAAAAAIfBTesSAAAA0xF0AwAAAMBhoEc3AACA+Qi6AQAAAOAwRHp0+wi6AQAAzELQDQAAAACHgRXdAAAA5iPoBgAAANCuNm3apLvuuksXX3yxioqKJEkffPCBVq1aZXJl0aFHNwAAgPkIugEAAAC0m08//VTDhg3T119/rTfeeENVVVWSpOXLl+vee+81ubroeJzht1W1tC4BAAAwTYcIup9++mn16tVLbrdb48eP16JFiw56fllZma677jrl5OTI5XLpiCOO0Pvvv99O1QIAAACI1m233aYHH3xQc+fOldPpjBw/4YQT9NVXX5lYWfQaWpd4WdENAABgGrvZBcyePVvTp0/XrFmzNH78eD3++OM65ZRTtG7dOmVlZTU53+fz6aSTTlJWVpZee+015eXladu2bUpJSWn/4gEAAAAckhUrVujll19ucjwrK0slJSUmVHT46NENAABgPtOD7pkzZ+rKK6/UtGnTJEmzZs3Se++9pxdeeEG33XZbk/NfeOEFlZaW6ssvv5TD4ZAk9erVqz1LBgAAABCllJQU7dmzR7179250fOnSpcrLyzOpqsPjdtYH3bQuAQAAMI2prUt8Pp8WL16syZMnR45ZrVZNnjxZCxcubPYxb7/9tiZMmKDrrrtO2dnZGjp0qB5++GEFg81PKuvq6lRRUdHoBgAAAMAcF110kX7961+roKBAFotFoVBIX3zxhW699VZddtllLXqOjjbHZ0U3AACA+aIOul966SVNmjRJubm52rZtmyTp8ccf11tvvdXi5ygpKVEwGFR2dnaj49nZ2SooKGj2MZs3b9Zrr72mYDCo999/X3fffbcee+wxPfjgg82eP2PGDCUnJ0du+fn5La4PAAAAQOt6+OGHNXDgQOXn56uqqkqDBw/Wscceq4kTJ+quu+5q0XN0tDk+PboBAADMF1XQ/cwzz2j69Ok6/fTTVVZWFllNnZKSoscff7w162siFAopKytLzz77rMaMGaMLL7xQd955p2bNmtXs+bfffrvKy8sjtx07drRpfQAAAAAOzOl06rnnntPmzZv17rvv6h//+IfWrl2rl156STabrUXP0dHm+B4nK7oBAADMFlWP7ieffFLPPfeczjnnHD3yyCOR42PHjtWtt97a4ufJyMiQzWZTYWFho+OFhYXq1q1bs4/J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ourR/dRTT2njxo3Kzc1Vz549m+yUvmTJklYpLhYlusM/8ipWdAMAAKALevHFF/X888/rrLPOihwbPny48vLydO211+qhhx4ysbrDl5no0vrCKhVXec0uBQAAoEuJKug+55xzWrWIp59+Wr/73e9UUFCgESNG6Mknn9S4ceN+8HGvvvqqLr74Yp199tl68803W7WmttIQdNO6BAAAAF1RaWmpBg4c2OT4wIEDY+KK0azE8IbzrOgGAABoX1EF3ffee2+rFTB79mxNnz5ds2bN0vjx4/X444/rlFNO0bp165SVlXXAx23dulW33nqrjjnmmFarpT0kuGldAgAAgK5rxIgReuqpp/TEE080Ov7UU09pxIgRJlXVemhdAgAAYI6ogu4Gixcv1po1ayRJQ4YM0ahRow75OWbOnKkrr7xS06ZNkyTNmjVL7733nl544QXddtttzT4mGAxqypQpuu+++/T555+rrKws6tfQ3iKbUdaxohsAAABdz6OPPqozzjhDH330kSZMmCBJWrhwoXbs2KH333/f5OoOX2YCQTcAAIAZogq6i4qKdNFFF2n+/PlKSUmRJJWVlen444/Xq6++qszMzBY9j8/n0+LFi3X77bdHjlmtVk2ePFkLFy484OPuv/9+ZWVl6YorrtDnn39+0O9RV1enurrvJ5kVFRUtqq2t0LoEAAAAXdlxxx2n9evX6+mnn9batWslSeeee66uvfZa5ebmtug5Otocf3+RFd1VBN0AAADtyRrNg2644QZVVlZq1apVKi0tVWlpqVauXKmKigrdeOONLX6ekpISBYNBZWdnNzqenZ2tgoKCZh+zYMEC/eUvf9Fzzz3Xou8xY8YMJScnR275+fktrq8tJLpoXQIAAICu5dxzz42E0X//+9+Vnp6uhx56SK+//rpef/11Pfjggy0OuaWON8ffX0PQXVRB0A0AANCeogq658yZoz/96U8aNGhQ5NjgwYP19NNP64MPPmi14v5XZWWlfvrTn+q5555TRkZGix5z++23q7y8PHLbsWNHm9XXEg2tS6poXQIAAIAu4t1331V1dbUkadq0aSovLz+s5+toc/z9saIbAADAHFG1LgmFQnI4HE2OOxwOhUKhFj9PRkaGbDabCgsLGx0vLCxUt27dmpy/adMmbd26VWeeeWajWiTJbrdr3bp16tu3b6PHuFwuuVyuFtfU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MEHz5s3TzTffHDk2d+5cTZgwodnzXS6XXC5Xo2MpKSmtUf4hS0pK4j/eGMOYxhbGM/YwprGF8Yw9bTWmrOSOfczx0ZYY09jCeMYexjS2MJ6xxez5vemtS6ZPn66pU6dq7NixGjdunB5//HFVV1dr2rRpkqTLLrtMeXl5mjFjhiTppptu0nHHHafHHntMZ5xxhl599VV9++23evbZZ818GQAAAAAAAAAAk5gedF944YUqLi7WPffco4KCAo0cOVJz5syJbDi5fft2Wa3WyPkTJ07Uyy+/rLvuukt33HGH+vfvrzfffFNDhw416yUAAAAAAAAAAExketAtSddff/0BW5XMnz+/ybHzzz9f559/fhtX1XpcLpfuvffeJpdXovNiTGML4xl7GNPYwnjGHsYUsYDf49jDmMYWxjP2MKaxhfGMLR1lPC2GYRimVgAAAAAAAAAAwGGw/vApAAAAAAAAAAB0XATdAAAAAAAAAIBOjaAbAAAAAAAAANCpEXQDAAAAAAAAADo1gu528PTTT6tXr15yu90aP368Fi1aZHZJaIEZM2boyCOPVGJiorKysnTOOedo3bp1jc7xer267rrrlJ6eroSEBJ133nkqLCw0qWIcikceeUQWi0U333xz5Bjj2fns2rVLl156qdLT0+XxeDRs2DB9++23kfsNw9A999yjnJwceTweTZ48WRs2bDCxYhxIMBjU3Xffrd69e8vj8ahv37564IEHtP+e2Yxnx/bZZ5/pzDPPVG5uriwWi958881G97dk/EpLSzVlyhQlJSUpJSVFV1xxhaqqqtrxVQAtxxy/c2KOH9uY48cG5vixgzl+59fZ5vgE3W1s9uzZmj59uu69914tWbJEI0aM0CmnnKKioiKzS8MP+PTTT3Xdddfpq6++0ty5c+X3+3XyySeruro6cs4tt9yid955R//+97/16aefavfu3Tr33HNNrBot8c033+jPf/6zhg8f3ug449m57Nu3T5MmTZLD4dAHH3yg1atX67HHHlNqamrknEcffVRPPPGEZs2apa+//lrx8fE65ZRT5PV6Tawczfntb3+rZ555Rk899ZTWrFmj3/72t3r00Uf15JNPRs5hPDu26upqjRgxQk8//XSz97dk/KZMmaJVq1Zp7ty5evfdd/XZZ5/pqquuaq+XALQYc/zOizl+7GKOHxuY48cW5vidX6eb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MWOGevfuLY/HoxEjRui1116T9P0lh++9956GDx8ut9uto446SitXrmz0HK+//rqGDBkil8ulXr166bHHHmt0f11dnX79618rPz9fLpdL/fr101/+8pdG5yxevFhjx45VXFycJk6cqHXr1rXtCwcAAABiFHN8AGhbBN0A0AHNmDFDf//73zVr1iytWrVKt9xyiy699FJ9+umnkXN++ctf6rHHHtM333yjzMxMnXnmmfL7/ZLCk9cLLrhAF110kVasWKHf/OY3uvvuu/W3v/0t8vjLLrtMr7zyip544gmtWbNGf/7zn5WQkNCojjvvvFOPPfaYvv32W9ntdl1++eXt8voBAACAWMMcHwDalsUwDMPsIgAA36urq1NaWpo++ugjTZgwIXL85z//uWpqanTVVVfp+OOP16uvvqoLL7xQklRaWqru3bvrb3/7my644AJNmTJFxcXF+vDDDyOP/9WvfqX33ntPq1at0vr16zVgwADNnTtXkydPblLD/Pnzdfzxx+ujjz7SiSeeKEl6//33dcYZZ6i2tlZut7uNfwoAAABA7GCODwBtjxXdANDBbNy4UTU1NTrppJOUkJAQuf3973/Xpk2bIuftP0FOS0vTgAEDtGbNGknSmjVrNGnSpEbPO2nSJG3YsEHBYFDLli2TzWbTcccdd9Bahg8fHvlzTk6OJKmoqOiwXyMAAADQlTDHB4C2Zze7AABAY1VVVZKk9957T3l5eY3uc7lcjSbC0fJ4PC06z+FwRP5ssVgkhXsLAgAAAGg55vgA0PZY0Q0AHczgwYPlcrm0fft29evXr9EtPz8/ct5XX30V+fO+ffu0fv16DRo0SJI0aNAgffHFF42e94svvtARRxwhm82mYcOGKRQKNeoHCAAAAKBtMMcHgLbHim4A6GASExN166236pZbblEoFNLRRx+t8vJyffHFF0pKSlLPnj0lSffff7/S09OVnZ2tO++8UxkZGTrnnHMkSb/4xS905JFH6oEHHtCFF16ohQsX6qmnntKf/vQnSVKvXr00depUXX755XriiSc0YsQIbdu2TUVFRbrgggvMeukAAABATGKODwBtj6AbADqgBx54QJmZmZoxY4Y2b96slJQUjR49WnfccUfkssJHHnlEN910kzZs2KCRI0fqnXfekdPplCSNHj1a//rXv3TPPffogQceUE5Oju6//3797Gc/i3yPZ555RnfccYeuvfZa7d27Vz169NAdd9xhxssFAAAAYh5zfABoWxbDMAyziwAAtFzDbun79u1TSkqK2eUAAAAAOEzM8QHg8NGjGwAAAAAAAADQqRF0AwAAAAAAAAA6NVqXAAAAAAAAAAA6NVZ0AwAAAAAAAAA6NYJuAAAAAAAAAECnRtANAAAAAAAAAOjUCLoBAAAAAAAAAJ0aQTcAAAAAAAAAoFMj6AYAAAAAAAAAdGoE3QAAAAAAAACATo2gGwAAAAAAAADQqRF0AwAAAAAAAAA6tf8Pl3rNEjsGUMoAAAAASUVORK5CYII=", + "image/png": "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", "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABbYAAAFzCAYAAADi9V/1AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABOkklEQVR4nO3deXiU9b3//9c9e0I2whK2IKDWBRAXFBG3Hqmo/Ny/bgdbrD1y2uJxoeqp+tXWpWLby6W0HrTn26PHtu4etdrWVqnC0SIKLsUNUPZ9zZ7Mct/374+Z+84EAhliZu6ZyfNxXbmSzEwm75k7CR9e93veH8O2bVsAAAAAAAAAABQIn9cFAAAAAAAAAACwPwi2AQAAAAAAAAAFhWAbAAAAAAAAAFBQCLYBAAAAAAAAAAWFYBsAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAi2AQAAAAAAAAAFJeB1AdlmWZY2btyo8vJyGYbhdTkAAADoIbZtq7GxUUOGDJHPR79Gb8IaHwAAoDjtzxq/6IPtjRs3qra21usyAAAAkCXr1q3TsGHDvC4DOcQaHwAAoLhlssYv+mC7vLxcUvLJqKio8LgaAAAA9JSGhgbV1ta66z30HqzxAQAAitP+rPGLPth2XppYUVHBohcAAKAIMYqi92GNDwAAUNwyWeMzjBAAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAi2AQAAAAAAAAAFhWAbAAAAAAAAAFBQCLYBAAAAAAAAAAWFYBsAAAAAAAAAUFAItgEAAAAAAAAABYVgGwAAAAAAAABQUAJeFwAAAAAA+Wx7U1SLV+9Sn7BfJx08wOtyAAAAIDq2AQAAAGCfPt3YoO/+bonu+dPnXpcCAACAFIJtAAAAANiHoD/536ZYwvS4EgAAADgItgEAAABgH0KB5H+b4qbtcSUAAABwEGwDAAAAwD6EA07HtuVxJQAAAHAQbAMAAADAPjgd2zGTYBsAACBfEGwDAAAAwD6E/HRsAwAA5BtPg+3Zs2fr2GOPVXl5uQYOHKjzzjtPy5Yt63CbtrY2zZw5U/369VNZWZkuvPBCbdmyxaOKAQAAAPQ2QUaRAAAA5B1Pg+358+dr5syZeuedd/Taa68pHo/r9NNPV3Nzs3ub66+/Xi+//LKeffZZzZ8/Xxs3btQFF1zgYdUAAAAAehO3Y9u0ZNtsIAkAAJAPAl5+81dffbXD54899pgGDhyoJUuW6OSTT1Z9fb1+85vf6IknntA//dM/SZIeffRRHXbYYXrnnXd0/PHHe1E2AAAAgF7EmbEtSXHTVihgeFgNAAAAJI+D7d3V19dLkqqrqyVJS5YsUTwe1+TJk93bHHrooRo+fLgWLlzYabAdjUYVjUbdzxsaGrJcNQAAAIBs8nqNH04LtmOm1SHoBgAAgDfyZkVmWZauu+46TZo0SWPGjJEkbd68WaFQSFVVVR1uW1NTo82bN3d6P7Nnz1ZlZaX7Vltbm+3SAQAAAGSR12t8ZxSJxJxtAACAfJE3wfbMmTP18ccf66mnnvpK93PzzTervr7efVu3bl0PVQgAAADAC16v8X0+QwFfcvwIwTYAAEB+yItRJFdffbVeeeUVLViwQMOGDXMvHzRokGKxmOrq6jp0bW/ZskWDBg3q9L7C4bDC4XC2SwYAAACQI/mwxg/6fUpYJsE2AABAnvC0Y9u2bV199dV64YUX9Le//U0jR47scP0xxxyjYDCoefPmuZctW7ZMa9eu1cSJE3NdLgAAAIBeypmrHTNNjysBAACA5HHH9syZM/XEE0/opZdeUnl5uTs3u7KyUiUlJaqsrNR3vvMdzZo1S9XV1aqoqNC//du/aeLEiZ1uHAkAAAAA2eAG2wnb40oAAAAgeRxsz507V5J06qmndrj80Ucf1RVXXCFJeuCBB+Tz+XThhRcqGo1qypQp+o//+I8cVwoAAACgN3M2kIyZjCIBAADIB54G27bddbdDJBLRQw89pIceeigHFQEAAADAnsJuxzbBNgAAQD7wdMY2AAAAABSCEME2AABAXiHYBgAAAIAuBP1sHgkAAJBPCLYBAAAAoAt0bAMAAOQXgm0AAAAA6EL75pFd7xMEAACA7CPYBgAAAIAu0LENAACQXwi2AQAAAKALBNsAAAD5hWAbAAAAALrQHmyzeSQAAEA+INgGAAAAgC60z9imYxsAACAfEGwDAAAAQBfcYJtRJAAAAHmBYBsAAAAAuuCOIjFtjysBAACARLANAAAAAF1i80gAAID8QrANAAAAAF0g2AYAAMgvBNsAAAAA0IX2zSNNjysBAACARLANAAAAAF2iYxsAACC/EGwDAAAAQBfcjm2CbQAAgLxAsA0AAAAAXXA6tuOm7XElAAAAkAi2AQAAAKBLTrAdpWMbAAAgLxBsAwAAAEAX2jePJNgGAADIBwTbAAAAANCF9s0jTY8rAQAAgESwDQAAAABdCrJ5JAAAQF4h2AYAAACALoQDjCIBAADIJwTbAAAAANAFZxRJPGF7XAkAAAAkgm0AAAAA6FKIjm0AAIC8QrANAAAAAF0IMWMbAAAgrxBsAwAAAEAXnI7tKME2AABAXiDYBgAAAIAuBN2ObdPjSgAAACARbAMAAABAl8LM2AYAAMgrBNsAAAAA0AVnFEnctD2uBAAAABLBNgAAAAB0ydk80rRsmRbhNgAAgNcItgEAAACgC07HtiTF2EASAADAcwTbAAAAANAFgm0AAID8QrANAAAAAF0I+Az346hpelgJAAAAJIJtAAAAAOiSYRhsIAkAAJBHCLYBAAAAIAPh1AaSjCIBAADwHsE2AAAAAGTA6dgm2AYAAPAewTYAAAAAZIBgGwAAIH8QbAMAAABABtxgm80jAQAAPEewDQAAAAAZCKZmbEfp2AYAAPAcwTYAAAAAZCCUCrbjpu1xJQAAACDYBgAAAIAMMGMbAAAgfxBsAwAAAEAGCLYBAADyB8E2AAAAAGQgzOaRAAAAeYNgGwAAAAAy4MzYpmMbAADAewTbAAAAAJCBIME2AABA3iDYBgAAAIAMuDO2TdvjSgAAAECwDQAAAAAZYPNIAACA/EGwDQAAAAAZINgGAADIHwTbAAAAAJABd/NI0/S4EgAAABBsAwAAAEAG6NgGAADIHwTbAAAAAJABt2ObYBsAAMBzBNsAAAAAkAG3Y9u0Pa4EAAAABNsAAAAAkAFGkQAAAOQPgm0AAAAAyED75pEE2wAAAF4j2AYAAACADLR3bJseVwIAAACCbQAAAADIAJtHAgAA5A+CbQAAAADIQPvmkQTbAAAAXiPYBgAAAIAMOMF2PGF7XAkAAAA8DbYXLFigs88+W0OGDJFhGHrxxRc7XH/FFVfIMIwOb2eccYY3xQIAAADo1ZxRJFE6tgEAADznabDd3NyscePG6aGHHtrrbc444wxt2rTJfXvyySdzWCEAAAAAJLVvHkmwDQAA4LWAl9/8zDPP1JlnnrnP24TDYQ0aNChHFQEAAABA59qDbdPjSgAAAOBpsJ2JN998UwMHDlTfvn31T//0T7r77rvVr1+/vd4+Go0qGo26nzc0NOSiTAAAAABZki9r/KCfzSMBAADyRV5vHnnGGWfo8ccf17x58/TTn/5U8+fP15lnninT3HuHxOzZs1VZWem+1dbW5rBiAAAAAD0tX9b4YUaRAAAA5A3Dtu282NLbMAy98MILOu+88/Z6m5UrV+rAAw/U66+/rtNOO63T23TWzVFbW6v6+npVVFT0dNkAAADwSENDgyorK1nn9QL5ssZfvqVRpz+wQNV9Qnr/tm/k7PsCAAD0Fvuzxs/7USTpRo0apf79++uLL77Ya7AdDocVDodzXBkAAACAbMmXNX7IT8c2AABAvsjrUSS7W79+vXbs2KHBgwd7XQoAAACAXibEKBIAAIC84WnHdlNTk7744gv381WrVunDDz9UdXW1qqurdccdd+jCCy/UoEGD9OWXX+qmm27SQQcdpClTpnhYNQAAAIDeyA22TUu2bcswDI8rAgAA6L08DbYXL16sr3/96+7ns2bNkiRNnz5dc+fO1T/+8Q/993//t+rq6jRkyBCdfvrpuuuuu/LiZYgAAAAAepegv/0FrzHTUjjg97AaAACA3s3TYPvUU0/Vvvau/Mtf/pLDagAAAABg78KBtGA7QbANAADgpYKasQ0AAAAAXgmldWzHzb036AAAACD7CLYBAAAAIAM+n6GALzlXmw0kAQAAvEWwDQAAAAAZcjeQJNgGAADwFME2AAAAAGTIDbZN0+NKAAAAejeCbQAAAADIUDA1ZztKxzYAAICnCLYBAAAAIEPOBpKMIgEAAPAWwTYAAAAAZCicGkUSN22PKwEAAOjdCLYBAAAAIENsHgkAAJAfCLYBAAAAIENsHgkAAJAfCLYBAAAAIEPM2AYAAMgPBNsAAAAAkKFgKtiOEmwDAAB4imAbAAAAADLEjG0AAID8QLANAAAAABlygu24aXtcCQAAQO9GsA0AAAAAGWrv2GbzSAAAAC8RbAMAAABAhsLO5pEmo0gAAAC8RLANAAAAABlixjYAAEB+INgGAAAAgAwF/QTbAAAA+YBgGwAAAAAy5HRsRxlFAgAA4CmCbQAAAADIkBNsxxO2x5UAAAD0bgTbAAAAAJChkLt5pOlxJQAAAL0bwTYAAAAAZIjNIwEAAPIDwTYAAAAAZChMsA0AAJAXCLYBAAAAIENBdxQJwTYAAICXCLYBAAAAIEOMIgEAAMgPBNsAAAAAkKH2zSNtjysBAADo3Qi2AQAAAGRNa2urWlpa3M/XrFmjBx98UH/96189rKr72ju2TY8rAQAA6N0ItgEAAABkzbnnnqvHH39cklRXV6cJEybovvvu07nnnqu5c+d6XN3+YxQJAABAfiDYBgAAAJA177//vk466SRJ0nPPPaeamhqtWbNGjz/+uObMmeNxdfvPDbbZPBIAAMBTBNsAAAAAsqalpUXl5eWSpL/+9a+64IIL5PP5dPzxx2vNmjUeV7f/3BnbdGwDAAB4imAbAAAAQNYcdNBBevHFF7Vu3Tr95S9/0emnny5J2rp1qyoqKjyubv8xigQAACA/EGwDAAAAyJrbb79dN9xwg0aMGKEJEyZo4sSJkpLd20cddZTH1e0/p2M7btoeVwIAANC7dSvYfv/997V06VL385deeknnnXeebrnlFsVisR4rDgAAAEBh+z//5/9o7dq1Wrx4sV599VX38tNOO00PPPCAh5V1j9OxHaVjGwAAwFPdCrb/9V//VcuXL5ckrVy5UpdeeqlKS0v17LPP6qabburRAgEAAAAUtkGDBumoo46Sz+dTQ0ODXnzxRZWXl+vQQw/1urT91j6KxPS4EgAAgN6tW8H28uXLdeSRR0qSnn32WZ188sl64okn9Nhjj+n555/vyfoAAAAAFLCLL75Yv/rVryRJra2tGj9+vC6++GIdccQRBfl/B3fzSJOObQAAAC91K9i2bVuWlVzIvf766zrrrLMkSbW1tdq+fXvPVQcAAACgoC1YsEAnnXSSJOmFF16Qbduqq6vTnDlzdPfdd3tc3f5j80gAAID80K1ge/z48br77rv129/+VvPnz9fUqVMlSatWrVJNTU2PFggAAACgcNXX16u6ulqS9Oqrr+rCCy9UaWmppk6dqhUrVnhc3f5zOrYtW0rQtQ0AAOCZbgXbDz74oN5//31dffXVuvXWW3XQQQdJkp577jmdcMIJPVogAAAAgMJVW1urhQsXqrm5Wa+++qpOP/10SdKuXbsUiUQ8rm7/OR3bkhQ3bQ8rAQAA6N0C3fmiI444QkuXLt3j8p///Ofy+/1fuSgAAAAAxeG6667TtGnTVFZWpgMOOECnnnqqpOSIkrFjx3pbXDekB9uxhKWSEP//AQAA8EK3gu1169bJMAwNGzZMkvTuu+/qiSee0OGHH64ZM2b0aIEAAAAACtf3v/99HXfccVq3bp2+8Y1vyOdLBsOjRo0qyBnbAZ8hw5BsW4qapqSg1yUBAAD0St0aRfLP//zPeuONNyRJmzdv1je+8Q29++67uvXWW3XnnXf2aIEAAAAACtv48eN1/vnnq0+fPrLt5PiOqVOnatKkSR5Xtv8Mw1DQzwaSAAAAXutWsP3xxx/ruOOOkyQ988wzGjNmjP7+97/r97//vR577LGerA8AAABAgXv88cc1duxYlZSUqKSkREcccYR++9vfel1Wt4UJtgEAADzXrVEk8Xhc4XBYkvT666/rnHPOkSQdeuih2rRpU89VBwAAAKCg3X///brtttt09dVXux3ab731lr773e9q+/btuv766z2ucP+FAj4pKsVMgm0AAACvdCvYHj16tB5++GFNnTpVr732mu666y5J0saNG9WvX78eLRAAAABA4frlL3+puXPn6lvf+pZ72TnnnKPRo0frxz/+ceEG25LiCdvjSgAAAHqvbo0i+elPf6pHHnlEp556qi677DKNGzdOkvSHP/zBHVECAAAAAJs2bdIJJ5ywx+UnnHBCwb7a0wm2Y6bpcSUAAAC9V7c6tk899VRt375dDQ0N6tu3r3v5jBkzVFpa2mPFAQAAAChsBx10kJ555hndcsstHS5/+umndfDBB3tU1VcTSs3YjjJjGwAAwDPdCrYlye/3K5FI6K233pIkHXLIIRoxYkRP1QUAAACgCNxxxx265JJLtGDBAnfG9ttvv6158+bpmWee8bi67gmyeSQAAIDnujWKpLm5WVdeeaUGDx6sk08+WSeffLKGDBmi73znO2ppaenpGgEAAAAUqAsvvFCLFi1S//799eKLL+rFF19U//799e677+r888/3urxucUeREGwDAAB4plsd27NmzdL8+fP18ssvd9jZ/JprrtEPfvADzZ07t0eLBAAAAFC4jjnmGP3ud7/zuowe0z5jm2AbAADAK90Ktp9//nk999xzOvXUU93LzjrrLJWUlOjiiy8m2AYAAAB6sYaGhoxvW1FRkcVKsiOcCrbjBNsAAACe6Vaw3dLSopqamj0uHzhwIKNIAAAAgF6uqqpKhmHs8za2bcswDJmmmaOqek6IGdsAAACe61awPXHiRP3oRz/S448/rkgkIklqbW3VHXfcoYkTJ/ZogQAAAAAKyxtvvOF1CVnFjG0AAADvdSvY/sUvfqEpU6Zo2LBhGjdunCTpo48+UiQS0V/+8pceLRAAAABA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", - "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -399,21 +371,22 @@ " key = headers[idx]\n", " data_dict[key].append(float(value))\n", "\n", - "for key in keys:\n", - " fig, axes = plt.subplots(1, 2, sharey=True, sharex=True, figsize=(18, 4))\n", + "fig, axes = plt.subplots(2, 2, constrained_layout=True)\n", + "axes = axes.ravel()\n", + "fig.suptitle(f'Metrics', fontsize=16)\n", "\n", + "for id, key in enumerate(keys):\n", " val = np.array(data_dict[f\"val_{key}\"])\n", " train = np.array(data_dict[f\"train_{key}\"])\n", " epoch = np.array(data_dict[\"epoch\"])\n", "\n", - " axes[0].plot(epoch, val)\n", - " axes[1].plot(epoch, train)\n", + " axes[id].plot(epoch, val, label=\"val data\")\n", + " # axes[id].plot(epoch, train, label=\"train data\")\n", + "\n", + " axes[id].set_ylabel(f\"{key}\")\n", + " axes[id].set_xlabel(r\"epoch\")\n", "\n", - " axes[0].set_ylabel(f\"val_{key}\")\n", - " axes[0].set_xlabel(r\"epoch\")\n", - " axes[1].set_ylabel(f\"train_{key}\")\n", - " axes[1].set_xlabel(r\"epoch\")\n", - " fig.show()" + "plt.show()" ] }, { @@ -430,6 +403,26 @@ "cell_type": "code", "execution_count": 11, "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 407.03it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 7.14it/s, test_loss=0.06859629925320611]\n" + ] + } + ], + "source": [ + "from apax.train.eval import eval_model\n", + "\n", + "eval_model(config_dict, n_test=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, "outputs": [ { "name": "stderr", @@ -443,16 +436,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[33mUsage: \u001b[0mapax [OPTIONS] COMMAND [ARGS]...\n", - "\u001b[2mTry \u001b[0m\u001b[2;34m'apax \u001b[0m\u001b[1;2;34m-h\u001b[0m\u001b[2;34m'\u001b[0m\u001b[2m for help.\u001b[0m\n", - "\u001b[31m╭─\u001b[0m\u001b[31m Error \u001b[0m\u001b[31m─────────────────────────────────────────────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n", - "\u001b[31m│\u001b[0m No such command 'evaluate'. \u001b[31m│\u001b[0m\n", - "\u001b[31m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5912.47it/s]\n", + "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.50it/s, test_loss=0.5443810628577777]\n" ] } ], "source": [ - "!apax evaluate config_minimal.yaml" + "!apax eval config.yaml --n-data 10" ] }, { @@ -469,15 +459,78 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## A Closer Look At Training Parameters\n", - "\n", - "TODO" + "## A Closer Look At Training Parameters" ] }, { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "| Parameter | Default Value | Description |\n", + "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", + "| **n_epochs** | `` | Number of training epochs. |\n", + "| **seed** | 1 | Seed for initializing random numbers. |\n", + "| **patience** | None | Number of epochs without improvement before training termination. |\n", + "| **n_models** | 1 | Number of models trained simultaneously. |\n", + "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", + "| **Data** | | |\n", + "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", + "| experiment | apax | Model name distinguishing from others in directory. |\n", + "| data_path | `` | Path to single dataset file. |\n", + "| train_data_path | `` | Path to training dataset. |\n", + "| val_data_path | `` | Path to validation dataset. |\n", + "| test_data_path | `` | Path to test dataset. |\n", + "| n_train | 1000 | Number of training data points. |\n", + "| n_valid | 100 | Number of validation data points. |\n", + "| batch_size | 32 | Number of training examples evaluated at once. |\n", + "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", + "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", + "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", + "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", + "| pos_unit | Ang | Positional unit. |\n", + "| energy_unit | eV | Energy unit. |\n", + "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", + "| **Model** | | |\n", + "| n_basis | 7 | Number of Gaussian basis functions. |\n", + "| n_radial | 5 | Number of contracted basis functions. |\n", + "| nn | [512, 512] | Hidden layers and units. |\n", + "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", + "| r_min | 0.5 | Descriptor cutoff radius. |\n", + "| use_zbl | false | Use Zero-Body-Loss. |\n", + "| b_init | normal | Initialization scheme for biases. |\n", + "| descriptor_dtype | fp64 | Descriptor data type. |\n", + "| readout_dtype | fp32 | Readout data type. |\n", + "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", + "| **Loss** | | |\n", + "| loss_type | structures | Weighting scheme for atomic contributions. |\n", + "| name | energy | Quantity keyword. |\n", + "| weight | 1.0 | Weighting factor in loss function. |\n", + "| name | forces | Quantity keyword. |\n", + "| weight | 4.0 | Weighting factor in loss function. |\n", + "| **Metrics** | | |\n", + "| name | energy | Quantity keyword. |\n", + "| reductions | | List of reductions on target-prediction differences. |\n", + "| name | forces | Quantity keyword. |\n", + "| reductions | mae, mse | Reductions on target-prediction differences. |\n", + "| **Optimizer** | | |\n", + "| opt_name | adam | Optimizer name. |\n", + "| opt_kwargs | {} | Optimizer keyword arguments. |\n", + "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", + "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", + "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", + "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", + "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", + "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", + "| **Callbacks** | | |\n", + "| name | csv | Callback name. |\n", + "| **Progress Bar** | | |\n", + "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", + "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", + "| **Checkpoints** | | |\n", + "| ckpt_interval | 1 | Epochs between checkpoints. |\n", + "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", + "| reset_layers | [] | List of layers to reinitialize parameters. |\n" + ] }, { "cell_type": "markdown", @@ -488,11 +541,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "!rm -r project config.yaml error_config.yaml" + "!rm -r project config.yaml error_config.yaml eval.log" ] } ], diff --git a/examples/05_Full_Config.ipynb b/examples/05_Full_Config.ipynb new file mode 100644 index 00000000..64135e3b --- /dev/null +++ b/examples/05_Full_Config.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Complete Configuration File\n", + " \n", + "```yaml\n", + "n_epochs: # Number of training epochs.\n", + "seed: 1 # Seed for initialising random numbers\n", + "patience: None # Number of epochs without improvement before trainings gets terminated.\n", + "n_models: 1 # Number of models to be trained at once.\n", + "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. \n", + " # Can yield singificant speedups for small structures or small batch sizes.\n", + "\n", + "data:\n", + " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", + " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", + " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", + " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", + " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", + " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", + "\n", + " n_train: 1000 # Number of training datapoints from `data_path`.\n", + " n_valid: 100 # Number of validation datapoints from `data_path`.\n", + "\n", + " batch_size: 32 # Number of training examples to be evaluated at once.\n", + " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", + "\n", + " shift_method: \"per_element_regression_shift\"\n", + " shift_options:\n", + " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", + " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", + "\n", + " pos_unit: Ang\n", + " energy_unit: eV\n", + "\n", + " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", + "\n", + "model:\n", + " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", + " n_radial: 5 # Number of contracted basis functions.\n", + " nn: [512, 512] # Number of hidden layers and units in those layers.\n", + "\n", + " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", + " r_min: 0.5 # Cutoff radius of the descriptor.\n", + "\n", + " use_zbl: false # \n", + "\n", + " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", + " descriptor_dtype: fp64\n", + " readout_dtype: fp32\n", + " scale_shift_dtype: fp32\n", + "\n", + "loss:\n", + "- loss_type: structures # Weighting scheme for atomic contributions.\n", + " # See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", + " name: energy # Keyword of the quantity e.g `energy`.\n", + " weight: 1.0 # Weighting factor in the overall loss function.\n", + "- loss_type: structures\n", + " name: forces\n", + " weight: 4.0\n", + "\n", + "metrics:\n", + "- name: energy # Keyword of the quantity e.g `energy`.\n", + " reductions: # List of reductions performed on the difference between target and predictions.\n", + " # Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", + " - mae\n", + "- name: forces\n", + " reductions:\n", + " - mae\n", + " - mse\n", + "\n", + "optimizer:\n", + " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", + " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", + " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", + " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", + " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", + " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", + " zbl_lr: 0.001 # \n", + " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", + "\n", + "callbacks:\n", + "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", + "\n", + "progress_bar:\n", + " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", + " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", + "\n", + "\n", + "checkpoints:\n", + " ckpt_interval: 1 # Number of epochs between checkpoints.\n", + " \n", + " # The options below are used for transfer learning\n", + " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", + " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", + "\n", + "```" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 3131982e6260b084a472aa4f9048a42e0161f731 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 13:38:45 +0100 Subject: [PATCH 084/192] changing utils function name --- examples/03_Transfer_Learning.ipynb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/03_Transfer_Learning.ipynb b/examples/03_Transfer_Learning.ipynb index 0412479f..a87e15ea 100644 --- a/examples/03_Transfer_Learning.ipynb +++ b/examples/03_Transfer_Learning.ipynb @@ -49,28 +49,30 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, + "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_md17_benzene_CCSDT, mod_md17\n", + "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets\n", "import os\n", "\n", "data_path = Path(\"project\")\n", - "file_path = download_md17_benzene_CCSDT(data_path)\n", + "file_path = download_md22_benzene_CCSDT(data_path)\n", "os.remove(data_path / \"benzene_ccsd_t-test.xyz\")\n", "\n", - "file_path = mod_md17(file_path)" + "file_path = mod_md_datasets(file_path)" ] } ], "metadata": { + "kernelspec": { + "display_name": "apax", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "name": "python", + "version": "3.11.8" } }, "nbformat": 4, From 8f4d969a1a6d59051a81350f3dcafed5c2079152 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 5 Mar 2024 13:54:07 +0100 Subject: [PATCH 085/192] clean up --- examples/01_Model_Training.ipynb | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index ad842eea..66b8d9be 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -246,22 +246,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "INFO | 11:21:13 | Initializing Callbacks\n", - "INFO | 11:21:13 | Initializing Loss Function\n", - "INFO | 11:21:13 | Initializing Metrics\n", - "INFO | 11:21:13 | Running Input Pipeline\n", - "INFO | 11:21:13 | Read data file project/benzene_mod.xyz\n", - "INFO | 11:21:13 | Loading data from project/benzene_mod.xyz\n", - "INFO | 11:21:24 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12020.13it/s]\n", - "INFO | 11:21:24 | Computing per element energy regression.\n", - "INFO | 11:21:31 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12084.55it/s]\n", - "INFO | 11:21:32 | Initializing Model\n", - "INFO | 11:21:32 | initializing 1 models\n", - "INFO | 11:21:38 | Initializing Optimizer\n", - "INFO | 11:21:38 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" + "INFO | 13:41:50 | Initializing Callbacks\n", + "INFO | 13:41:50 | Initializing Loss Function\n", + "INFO | 13:41:50 | Initializing Metrics\n", + "INFO | 13:41:50 | Running Input Pipeline\n", + "INFO | 13:41:50 | Read data file project/benzene_mod.xyz\n", + "INFO | 13:41:50 | Loading data from project/benzene_mod.xyz\n", + "INFO | 13:42:00 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12919.46it/s]\n", + "INFO | 13:42:00 | Computing per element energy regression.\n", + "INFO | 13:42:06 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12653.65it/s]\n", + "INFO | 13:42:07 | Initializing Model\n", + "INFO | 13:42:08 | initializing 1 models\n", + "INFO | 13:42:13 | Initializing Optimizer\n", + "INFO | 13:42:13 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" ] } ], @@ -299,9 +299,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9622.30it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10820.94it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:35<00:00, 2.15s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9771.12it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 13090.43it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" ] } ], @@ -335,7 +335,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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99yWLLZq1YpnnnmGiIgIRowYwebNm9116mt3hcLc+yVZFELcyKQotxC657ZkcebMmZw5c4Z58+aRlJTELbfcQuPGjXn77bcvW5Wg0immMLeqqhdbFqXothDiEjVr1rysYPd1SUrnCKF7bh2zaDKZuO+++1i6dCmnTp1i4MCBvPDCC0RHR3PPPffw+++/uzOcknMmi67d0GfTcknNtmE0KNQN8/dAYEIId4uPj+fUqVPO51u3bmXs2LF88sknLvvt3bu39OswV0ZSOkcI3fPIBJetW7cydepU3nnnHcLCwpg0aRKhoaHceeedPPPMM54I6coKk8W/TXAp7IKuW80fby8plSOEHgwcOJDVq1cDkJCQQK9evdi6dSvPP/88L7/8soejqwBSOkcI3XNbspiUlMQ777xD06ZN6dq1K+fOneOrr77ixIkTvPTSS3z66aesWLGC2bNnuyukkru0MPclCmdCSxe0EPqxd+9e2rdvD8DXX39N06ZN2bhxI19++WWRhbSve8aCbmhpWRRCt9xWZ7FGjRrUqVOHYcOGMXToUKpVq3bZPs2bN6ddu3buCqnknLOhXVsWC8crNooMcHdEQggPsdlsWCxab8Nvv/1G//79AWjYsCFnz571ZGgVwyClc4TQO7cli6tWraJr165X3CcwMNDZvVOpFNOy+Fdhy2KkLO0nhF40adKE2bNnc8cdd7By5UpeeeUVAM6cOUPVqlU9HF0FMEjLohB657Zu6KslipVa4aotl4xZjE/JJi4lG6NBkXWghdCRN954g48//pju3bszYMAAWrRoAcAPP/zg7J6+oRhlzKIQeue2lsVWrVoVucKJoih4e3tTt25dhg4dSo8ePdwVUskV0bK47vA5AFpFBxPkcwOUxxBClEj37t1JTk4mPT2dKlWqOLc//vjj+Pr6ejCyCuJsWZRuaCH0ym0ti3369OHYsWP4+fnRo0cPevTogb+/P0ePHqVdu3acPXuWnj17snTpUneFVHLOMYsX6yyuPagli93qXz72UghxY1NVldjYWD7++GMyMjIAMJvNN2ayKEW5hdA9t7UsJicn869//YsXXnjBZfurr77KyZMnWbFiBVOnTuWVV17h7rvvdldYJeNsWdSSRZvdwcaj5wHo1kCSRSH05OTJk/Tp04e4uDjy8vLo1asXAQEBvPHGG+Tl5VXOig7XQkrnCKF7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LUIPM5sMmAwKVrXw27W0LAohXB0/fpzGjRsD8N1333HnnXcybdo0Zs2axS+//FLi42RlZdGiRQtmzZpV5Otvvvkm77//PrNnz2bLli34+fnRu3dvcnMr8EusFOUWQvfKlCwOHDiQ1atXA5CQkECvXr3YunUrzz//PC+//HK5BlgZ+HgZL2lZlDGLQghXZrOZ7OxsAH777Tduv/12AEJCQpwtjiXRt29fXn31Ve69997LXlNVlZkzZzJ58mTuvvtumjdvzvz58zlz5sxlLZDlyrncn7QsCqFXZUoW9+7dS/v27QH4+uuvadq0KRs3buTLL7/k888/L8/4KgWfS9eHlgkuQoi/6dKlC+PHj+eVV15h69atzmX/Dh06RI0aNcrlHMePHychIYGePXs6twUFBdGhQwc2bdpU5Hvy8vJIT093eZSalM4RQvfKlCzabDYsFgugfYvu378/AA0bNuTs2bPlF10l4WM2koeUzhFCFO2DDz7AZDLx7bff8tFHH1G9enUAfvnlF/r06VMu50hISAAgPDzcZXt4eLjztb+bPn06QUFBzkeZhgVJ6RwhdK9MpXOaNGnC7NmzueOOO1i5ciWvvPIKAGfOnHHWF7uRuHZDywQXIYSrmJgYfvrpp8u2v/vuux6I5qJJkya5TLBJT08vfcIopXOE0L0yJYtvvPEG9957L2+99RZDhgyhRYsWAPzwww/O7ukbiY/ZSIbqoz3Jy/BsMEKISslut7NkyRL2798PaF+q+/fvj9FoLJfjR0REAJCYmEhkZKRze2JiIi1btizyPRaLxdkLVGay3J8Qulembuju3buTnJxMcnIyc+fOdW5//PHHmT17dqmPN2vWLGrVqoW3tzcdOnRg69atJXrfwoULURSFe+65p9TnLA1fs5E0/LQnuakVei4hxPXnyJEjNGrUiMGDB7N48WIWL17MI488QpMmTTh69Gi5nKN27dpERESwatUq57b09HS2bNlCx44dy+UcRTJK6Rwh9K7MdRZVVSU2NpaPP/6YjAyttc1sNuPr61uq4yxatIjx48czdepUduzYQYsWLejduzdJSUlXfN+JEyd45pln6Nq1a1kvocR8vIykqwXJYs51XmBXCFHunn76aerUqUN8fDw7duxgx44dxMXFUbt2bZ5++ukSHyczM5Ndu3axa9cuQJvUsmvXLuLi4lAUhbFjx/Lq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5s+fz6233spbb73Fj370IzweD3PmzEnGd6z9J92xA9x88800NjYyYsQILMsikUhw9913M3v2bIBeH3+77sRZXV1NYWFhynqXy0Vubm6v6ktvovmvZ2j+Sw/Nfyef/7RYPI3MnTuXTZs28cYbb6Q7lG7Zs2cP8+bNY+nSpfh8vnSHc1Js26aiooJf/epXAIwbN45NmzbxyCOPMGfOnDRHd2J/+9vfeOKJJ3jyySc555xz2LhxI9dffz0lJSV9In6ljqT5r+do/jvz6MfQXcjPz8eyrKO+eVZTU0NxcXGaouraddddx4svvsjrr7/OwIEDk8uLi4uJRqPU19entO8N/Vi/fj21tbWcf/75uFwuXC4XK1as4IEHHsDlclFUVNRrY+/fvz+jRo1KWTZy5Eh2794NkIyvt+4/N954IzfffDPf/OY3GT16NN/5zne44YYbWLBgAdD742/XnTiLi4upra1NWR+Px6mrq+tVfelNNP+depr/0kfz38nnPy0Wu+DxeLjgggtYtmxZcplt2yxbtoxJkyalMbJUIsJ1113Hs88+y2uvvcbgwYNT1l9wwQW43e6UflRVVbF79+609+Piiy/mvffeY+PGjclbRUUFs2fPTv7eW2OfMmXKUVN0bN26lUGDBgEwePBgiouLU2JvbGxkzZo1aY8doLW1FdNMfflbloVt20Dvj79dd+KcNGkS9fX1rF+/Ptnmtddew7ZtKisrezzmvkDz36mn+S99NP99gvz3ab+dczpbtGiReL1e+eMf/ygffPCBfP/735dgMCjV1dXpDi3p2muvlZycHFm+fLns378/eWttbU22ueaaa6SsrExee+01WbdunUyaNEkmTZqUxqi71vnbgCK9N/a1a9eKy+WSu+++W7Zt2yZPPPGEBAIB+ctf/pJsc88990gwGJTnn39e3n33XfnKV77Sa6aOmDNnjgwYMCA5dcQzzzwj+fn58tOf/jTZprfE39TUJBs2bJANGzYIIL/5zW9kw4YN8tFHH3U7zksvvVTGjRsna9askTfeeEOGDRumU+ecgOa/nqf5r2do/jv5/KfF4gk8+OCDUlZWJh6PRyZMmCCrV69Od0gpgGPeFi5cmGwTCoXkBz/4gfTr108CgYB89atflf3796cv6OM4Mln25thfeOEFOffcc8Xr9cqIESPk0UcfTVlv27bcfvvtUlRUJF6vVy6++GKpqqpKU7SpGhsbZd68eVJWViY+n0+GDBkit912m0QikWSb3hL/66+/fsx9fM6cOd2O89ChQzJr1izJzMyU7OxsufLKK6WpqanH+9LXaP7rWZr/eobmv5PPf4ZIpynLlVJKKaWU6kTPWVRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSXtFhUSimllFJd0mJRKaWUUkp1SYtFpZRSSinVJS0WlVJKKaVUl7RYVKobli9fjmEY1NfXpzsUpZTqUZr/lBaLSimllFKqS1osKqWUUkqpLmmxqPoE27ZZsGABgwcPxu/3M3bsWJ5++mmg4yOSJUuWMGbMGHw+HxMnTmTTpk0p9/H3v/+dc845B6/XS3l5Offdd1/K+kgkwk033URpaSler5ehQ4fyhz/8IaXN+vXrqaioIBAIMHnyZKqqqk5tx5VSZzzNfyrtRKk+4Je//KWMGDFCXn75Zdm+fbssXLhQvF6vLF++XF5//XUBZOTIkfLKK6/Iu+++K1/84helvLxcotGoiIisW7dOTNOUO++8U6qqqmThwoXi9/tl4cKFyce4/PLLpbS0VJ555hnZvn27vPrqq7Jo0SIRkeRjVFZWyvLly+X999+Xz33uczJ58uR0PB1KqTOI5j+Vblosql4vHA5LIBCQN998M2X51VdfLbNmzUomsvbEJiJy6NAh8fv98tRTT4mIyLe+9S255JJLUra/8cYbZdSoUSIiUlVVJYAsXbr0mDG0P8arr76aXLZkyRIBJBQKfSb9VEqpI2n+U72Bfgyter0PP/yQ1tZWLrnkEjIzM5O3P//5z2zfvj3ZbtKkScnfc3NzOfvss9m8eTMAmzdvZsqUKSn3O2XKFLZt20YikWDjxo1YlsXUqVOPG8uYMWOSv/fv3x+A2traT91HpZQ6Fs1/qjdwpTsApU6kubkZgCVLljBgwICUdV6vNyVhflJ+v79b7dxud/J3wzAA53wipZQ6FTT/qd5ARxZVrzdq1Ci8Xi+7d+9m6NChKbfS0tJku9WrVyd/P3z4MFu3bmXkyJEAjBw5kpUrV6bc78qVKxk+fDiWZTF69Ghs22bFihU90ymllOoGzX+qN9CRRdXrZWVl8ZOf/IQbbrgB27a58MILaWhoYOXKlWRnZzNo0CAA7rzzTvLy8igqKuK2224jPz+fGTNmAPDjH/+Y8ePHc9dddzFz5kxWrVrFQw89xO9+9zsAysvLmTNnDldddRUPPPAAY8eO5aOPPqK2tpbLL788XV1XSp3hNP+pXiHdJ00q1R22bcv9998vZ599trjdbikoKJDp06fLihUrkidfv/DCC3LOOeeIx+ORCRMmyDvvvJNyH08//bSMGjVK3G63lJWVyb333puyPhQKyQ033CD9+/cXj8cjQ4cOlccff1xEOk7wPnz4cLL9hg0bBJCdO3ee6u4rpc5gmv9UuhkiIuksVpX6tJYvX85FF13E4cOHCQaD6Q5HKaV6jOY/1RP0nEWllFJKKdUlLRaVUkoppVSX9GNopZRSSinVJR1ZVEoppZRSXdJiUSmllFJKdUmLRaWUUkop1SUtFpVSSimlVJe0WFRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSX/j9nEtQsXpP9AgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -381,7 +381,7 @@ " epoch = np.array(data_dict[\"epoch\"])\n", "\n", " axes[id].plot(epoch, val, label=\"val data\")\n", - " # axes[id].plot(epoch, train, label=\"train data\")\n", + " axes[id].plot(epoch, train, label=\"train data\")\n", "\n", " axes[id].set_ylabel(f\"{key}\")\n", " axes[id].set_xlabel(r\"epoch\")\n", @@ -408,8 +408,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 407.03it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 7.14it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 280.00it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.29it/s, test_loss=0.06859629925320611]\n" ] } ], @@ -436,8 +436,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5912.47it/s]\n", - "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.50it/s, test_loss=0.5443810628577777]\n" + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5706.54it/s]\n", + "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.48it/s, test_loss=0.5443810628577777]\n" ] } ], From f40797081362e450ef2b7b5f7abcc73165568819 Mon Sep 17 00:00:00 2001 From: Nico Segreto Date: Tue, 5 Mar 2024 14:10:15 +0100 Subject: [PATCH 086/192] Moredocs nico (#238) eval tmp bug fix --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- apax/train/eval.py | 7 ++-- examples/01_Model_Training.ipynb | 50 ++++++++++++++--------------- examples/03_Transfer_Learning.ipynb | 20 ++++++------ 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/apax/train/eval.py b/apax/train/eval.py index 8a504c2b..67ce1dda 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -85,9 +85,9 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal 0, test_steps_per_epoch, desc="Batches", ncols=100, disable=False, leave=True ) for batch_idx in range(test_steps_per_epoch): - inputs, labels = next(batch_test_ds) + batch = next(batch_test_ds) - batch_loss, test_metrics = test_step_fn(params, inputs, labels, test_metrics) + batch_loss, test_metrics = test_step_fn(params, batch, test_metrics) epoch_loss["test_loss"] += batch_loss batch_pbar.set_postfix(test_loss=epoch_loss["test_loss"] / batch_idx) @@ -123,7 +123,8 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): raw_ds = load_test_data(config, model_version_path, eval_path, n_test) - test_ds = initialize_dataset(config, raw_ds, read_labels=False, calc_stats=False) + test_ds = initialize_dataset(config, raw_ds, read_labels=True, calc_stats=False) + test_ds.set_batch_size(1) # TODO temporary _, init_box = test_ds.init_input() diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index ad842eea..66b8d9be 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -246,22 +246,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "INFO | 11:21:13 | Initializing Callbacks\n", - "INFO | 11:21:13 | Initializing Loss Function\n", - "INFO | 11:21:13 | Initializing Metrics\n", - "INFO | 11:21:13 | Running Input Pipeline\n", - "INFO | 11:21:13 | Read data file project/benzene_mod.xyz\n", - "INFO | 11:21:13 | Loading data from project/benzene_mod.xyz\n", - "INFO | 11:21:24 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12020.13it/s]\n", - "INFO | 11:21:24 | Computing per element energy regression.\n", - "INFO | 11:21:31 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12084.55it/s]\n", - "INFO | 11:21:32 | Initializing Model\n", - "INFO | 11:21:32 | initializing 1 models\n", - "INFO | 11:21:38 | Initializing Optimizer\n", - "INFO | 11:21:38 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" + "INFO | 13:41:50 | Initializing Callbacks\n", + "INFO | 13:41:50 | Initializing Loss Function\n", + "INFO | 13:41:50 | Initializing Metrics\n", + "INFO | 13:41:50 | Running Input Pipeline\n", + "INFO | 13:41:50 | Read data file project/benzene_mod.xyz\n", + "INFO | 13:41:50 | Loading data from project/benzene_mod.xyz\n", + "INFO | 13:42:00 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12919.46it/s]\n", + "INFO | 13:42:00 | Computing per element energy regression.\n", + "INFO | 13:42:06 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12653.65it/s]\n", + "INFO | 13:42:07 | Initializing Model\n", + "INFO | 13:42:08 | initializing 1 models\n", + "INFO | 13:42:13 | Initializing Optimizer\n", + "INFO | 13:42:13 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" ] } ], @@ -299,9 +299,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9622.30it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10820.94it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:35<00:00, 2.15s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9771.12it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 13090.43it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" ] } ], @@ -335,7 +335,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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99yWLLZq1YpnnnmGiIgIRowYwebNm9116mt3hcLc+yVZFELcyKQotxC657ZkcebMmZw5c4Z58+aRlJTELbfcQuPGjXn77bcvW5Wg0immMLeqqhdbFqXothDiEjVr1rysYPd1SUrnCKF7bh2zaDKZuO+++1i6dCmnTp1i4MCBvPDCC0RHR3PPPffw+++/uzOcknMmi67d0GfTcknNtmE0KNQN8/dAYEIId4uPj+fUqVPO51u3bmXs2LF88sknLvvt3bu39OswV0ZSOkcI3fPIBJetW7cydepU3nnnHcLCwpg0aRKhoaHceeedPPPMM54I6coKk8W/TXAp7IKuW80fby8plSOEHgwcOJDVq1cDkJCQQK9evdi6dSvPP/88L7/8soejqwBSOkcI3XNbspiUlMQ777xD06ZN6dq1K+fOneOrr77ixIkTvPTSS3z66aesWLGC2bNnuyukkru0MPclCmdCSxe0EPqxd+9e2rdvD8DXX39N06ZN2bhxI19++WWRhbSve8aCbmhpWRRCt9xWZ7FGjRrUqVOHYcOGMXToUKpVq3bZPs2bN6ddu3buCqnknLOhXVsWC8crNooMcHdEQggPsdlsWCxab8Nvv/1G//79AWjYsCFnz571ZGgVwyClc4TQO7cli6tWraJr165X3CcwMNDZvVOpFNOy+Fdhy2KkLO0nhF40adKE2bNnc8cdd7By5UpeeeUVAM6cOUPVqlU9HF0FMEjLohB657Zu6KslipVa4aotl4xZjE/JJi4lG6NBkXWghdCRN954g48//pju3bszYMAAWrRoAcAPP/zg7J6+oRhlzKIQeue2lsVWrVoVucKJoih4e3tTt25dhg4dSo8ePdwVUskV0bK47vA5AFpFBxPkcwOUxxBClEj37t1JTk4mPT2dKlWqOLc//vjj+Pr6ejCyCuJsWZRuaCH0ym0ti3369OHYsWP4+fnRo0cPevTogb+/P0ePHqVdu3acPXuWnj17snTpUneFVHLOMYsX6yyuPagli93qXz72UghxY1NVldjYWD7++GMyMjIAMJvNN2ayKEW5hdA9t7UsJicn869//YsXXnjBZfurr77KyZMnWbFiBVOnTuWVV17h7rvvdldYJeNsWdSSRZvdwcaj5wHo1kCSRSH05OTJk/Tp04e4uDjy8vLo1asXAQEBvPHGG+Tl5VXOig7XQkrnCKF7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LUIPM5sMmAwKVrXw27W0LAohXB0/fpzGjRsD8N1333HnnXcybdo0Zs2axS+//FLi42RlZdGiRQtmzZpV5Otvvvkm77//PrNnz2bLli34+fnRu3dvcnMr8EusFOUWQvfKlCwOHDiQ1atXA5CQkECvXr3YunUrzz//PC+//HK5BlgZ+HgZL2lZlDGLQghXZrOZ7OxsAH777Tduv/12AEJCQpwtjiXRt29fXn31Ve69997LXlNVlZkzZzJ58mTuvvtumjdvzvz58zlz5sxlLZDlyrncn7QsCqFXZUoW9+7dS/v27QH4+uuvadq0KRs3buTLL7/k888/L8/4KgWfS9eHlgkuQoi/6dKlC+PHj+eVV15h69atzmX/Dh06RI0aNcrlHMePHychIYGePXs6twUFBdGhQwc2bdpU5Hvy8vJIT093eZSalM4RQvfKlCzabDYsFgugfYvu378/AA0bNuTs2bPlF10l4WM2koeUzhFCFO2DDz7AZDLx7bff8tFHH1G9enUAfvnlF/r06VMu50hISAAgPDzcZXt4eLjztb+bPn06QUFBzkeZhgVJ6RwhdK9MpXOaNGnC7NmzueOOO1i5ciWvvPIKAGfOnHHWF7uRuHZDywQXIYSrmJgYfvrpp8u2v/vuux6I5qJJkya5TLBJT08vfcIopXOE0L0yJYtvvPEG9957L2+99RZDhgyhRYsWAPzwww/O7ukbiY/ZSIbqoz3Jy/BsMEKISslut7NkyRL2798PaF+q+/fvj9FoLJfjR0REAJCYmEhkZKRze2JiIi1btizyPRaLxdkLVGay3J8Qulembuju3buTnJxMcnIyc+fOdW5//PHHmT17dqmPN2vWLGrVqoW3tzcdOnRg69atJXrfwoULURSFe+65p9TnLA1fs5E0/LQnuakVei4hxPXnyJEjNGrUiMGDB7N48WIWL17MI488QpMmTTh69Gi5nKN27dpERESwatUq57b09HS2bNlCx44dy+UcRTJK6Rwh9K7MdRZVVSU2NpaPP/6YjAyttc1sNuPr61uq4yxatIjx48czdepUduzYQYsWLejduzdJSUlXfN+JEyd45pln6Nq1a1kvocR8vIykqwXJYs51XmBXCFHunn76aerUqUN8fDw7duxgx44dxMXFUbt2bZ5++ukSHyczM5Ndu3axa9cuQJvUsmvXLuLi4lAUhbFjx/Lq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5s+fz6233spbb73Fj370IzweD3PmzEnGd6z9J92xA9x88800NjYyYsQILMsikUhw9913M3v2bIBeH3+77sRZXV1NYWFhynqXy0Vubm6v6ktvovmvZ2j+Sw/Nfyef/7RYPI3MnTuXTZs28cYbb6Q7lG7Zs2cP8+bNY+nSpfh8vnSHc1Js26aiooJf/epXAIwbN45NmzbxyCOPMGfOnDRHd2J/+9vfeOKJJ3jyySc555xz2LhxI9dffz0lJSV9In6ljqT5r+do/jvz6MfQXcjPz8eyrKO+eVZTU0NxcXGaouraddddx4svvsjrr7/OwIEDk8uLi4uJRqPU19entO8N/Vi/fj21tbWcf/75uFwuXC4XK1as4IEHHsDlclFUVNRrY+/fvz+jRo1KWTZy5Eh2794NkIyvt+4/N954IzfffDPf/OY3GT16NN/5zne44YYbWLBgAdD742/XnTiLi4upra1NWR+Px6mrq+tVfelNNP+depr/0kfz38nnPy0Wu+DxeLjgggtYtmxZcplt2yxbtoxJkyalMbJUIsJ1113Hs88+y2uvvcbgwYNT1l9wwQW43e6UflRVVbF79+609+Piiy/mvffeY+PGjclbRUUFs2fPTv7eW2OfMmXKUVN0bN26lUGDBgEwePBgiouLU2JvbGxkzZo1aY8doLW1FdNMfflbloVt20Dvj79dd+KcNGkS9fX1rF+/Ptnmtddew7ZtKisrezzmvkDz36mn+S99NP99gvz3ab+dczpbtGiReL1e+eMf/ygffPCBfP/735dgMCjV1dXpDi3p2muvlZycHFm+fLns378/eWttbU22ueaaa6SsrExee+01WbdunUyaNEkmTZqUxqi71vnbgCK9N/a1a9eKy+WSu+++W7Zt2yZPPPGEBAIB+ctf/pJsc88990gwGJTnn39e3n33XfnKV77Sa6aOmDNnjgwYMCA5dcQzzzwj+fn58tOf/jTZprfE39TUJBs2bJANGzYIIL/5zW9kw4YN8tFHH3U7zksvvVTGjRsna9askTfeeEOGDRumU+ecgOa/nqf5r2do/jv5/KfF4gk8+OCDUlZWJh6PRyZMmCCrV69Od0gpgGPeFi5cmGwTCoXkBz/4gfTr108CgYB89atflf3796cv6OM4Mln25thfeOEFOffcc8Xr9cqIESPk0UcfTVlv27bcfvvtUlRUJF6vVy6++GKpqqpKU7SpGhsbZd68eVJWViY+n0+GDBkit912m0QikWSb3hL/66+/fsx9fM6cOd2O89ChQzJr1izJzMyU7OxsufLKK6WpqanH+9LXaP7rWZr/eobmv5PPf4ZIpynLlVJKKaWU6kTPWVRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSXtFhUSimllFJd0mJRKaWUUkp1SYtFpZRSSinVJS0WlVJKKaVUl7RYVKobli9fjmEY1NfXpzsUpZTqUZr/lBaLSimllFKqS1osKqWUUkqpLmmxqPoE27ZZsGABgwcPxu/3M3bsWJ5++mmg4yOSJUuWMGbMGHw+HxMnTmTTpk0p9/H3v/+dc845B6/XS3l5Offdd1/K+kgkwk033URpaSler5ehQ4fyhz/8IaXN+vXrqaioIBAIMHnyZKqqqk5tx5VSZzzNfyrtRKk+4Je//KWMGDFCXn75Zdm+fbssXLhQvF6vLF++XF5//XUBZOTIkfLKK6/Iu+++K1/84helvLxcotGoiIisW7dOTNOUO++8U6qqqmThwoXi9/tl4cKFyce4/PLLpbS0VJ555hnZvn27vPrqq7Jo0SIRkeRjVFZWyvLly+X999+Xz33uczJ58uR0PB1KqTOI5j+Vblosql4vHA5LIBCQN998M2X51VdfLbNmzUomsvbEJiJy6NAh8fv98tRTT4mIyLe+9S255JJLUra/8cYbZdSoUSIiUlVVJYAsXbr0mDG0P8arr76aXLZkyRIBJBQKfSb9VEqpI2n+U72Bfgyter0PP/yQ1tZWLrnkEjIzM5O3P//5z2zfvj3ZbtKkScnfc3NzOfvss9m8eTMAmzdvZsqUKSn3O2XKFLZt20YikWDjxo1YlsXUqVOPG8uYMWOSv/fv3x+A2traT91HpZQ6Fs1/qjdwpTsApU6kubkZgCVLljBgwICUdV6vNyVhflJ+v79b7dxud/J3wzAA53wipZQ6FTT/qd5ARxZVrzdq1Ci8Xi+7d+9m6NChKbfS0tJku9WrVyd/P3z4MFu3bmXkyJEAjBw5kpUrV6bc78qVKxk+fDiWZTF69Ghs22bFihU90ymllOoGzX+qN9CRRdXrZWVl8ZOf/IQbbrgB27a58MILaWhoYOXKlWRnZzNo0CAA7rzzTvLy8igqKuK2224jPz+fGTNmAPDjH/+Y8ePHc9dddzFz5kxWrVrFQw89xO9+9zsAysvLmTNnDldddRUPPPAAY8eO5aOPPqK2tpbLL788XV1XSp3hNP+pXiHdJ00q1R22bcv9998vZ599trjdbikoKJDp06fLihUrkidfv/DCC3LOOeeIx+ORCRMmyDvvvJNyH08//bSMGjVK3G63lJWVyb333puyPhQKyQ033CD9+/cXj8cjQ4cOlccff1xEOk7wPnz4cLL9hg0bBJCdO3ee6u4rpc5gmv9UuhkiIuksVpX6tJYvX85FF13E4cOHCQaD6Q5HKaV6jOY/1RP0nEWllFJKKdUlLRaVUkoppVSX9GNopZRSSinVJR1ZVEoppZRSXdJiUSmllFJKdUmLRaWUUkop1SUtFpVSSimlVJe0WFRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSX/j9nEtQsXpP9AgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -381,7 +381,7 @@ " epoch = np.array(data_dict[\"epoch\"])\n", "\n", " axes[id].plot(epoch, val, label=\"val data\")\n", - " # axes[id].plot(epoch, train, label=\"train data\")\n", + " axes[id].plot(epoch, train, label=\"train data\")\n", "\n", " axes[id].set_ylabel(f\"{key}\")\n", " axes[id].set_xlabel(r\"epoch\")\n", @@ -408,8 +408,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 407.03it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 7.14it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 280.00it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.29it/s, test_loss=0.06859629925320611]\n" ] } ], @@ -436,8 +436,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5912.47it/s]\n", - "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.50it/s, test_loss=0.5443810628577777]\n" + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5706.54it/s]\n", + "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.48it/s, test_loss=0.5443810628577777]\n" ] } ], diff --git a/examples/03_Transfer_Learning.ipynb b/examples/03_Transfer_Learning.ipynb index 0412479f..a87e15ea 100644 --- a/examples/03_Transfer_Learning.ipynb +++ b/examples/03_Transfer_Learning.ipynb @@ -49,28 +49,30 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, + "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_md17_benzene_CCSDT, mod_md17\n", + "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets\n", "import os\n", "\n", "data_path = Path(\"project\")\n", - "file_path = download_md17_benzene_CCSDT(data_path)\n", + "file_path = download_md22_benzene_CCSDT(data_path)\n", "os.remove(data_path / \"benzene_ccsd_t-test.xyz\")\n", "\n", - "file_path = mod_md17(file_path)" + "file_path = mod_md_datasets(file_path)" ] } ], "metadata": { + "kernelspec": { + "display_name": "apax", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "name": "python", + "version": "3.11.8" } }, "nbformat": 4, From e4910a4dc303cf145f051d6f881072d0bbed8fb9 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 15:16:32 +0100 Subject: [PATCH 087/192] more docs --- apax/config/md_config.py | 2 +- examples/01_Model_Training.ipynb | 404 +++++++++++++++++++++++---- examples/02_Molecular_Dynamics.ipynb | 275 +++++++++++++++++- 3 files changed, 612 insertions(+), 69 deletions(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index f34a1889..989b04ea 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -60,7 +60,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. - intitial_structure: + initial_structure: Path to the starting structure of the simulation. sim_dir: Directory where simulation file will be stored. diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 66b8d9be..5e7ff30a 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -1,5 +1,15 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter('ignore')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -16,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -44,17 +54,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -100,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -132,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -168,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -194,7 +196,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -209,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -239,29 +241,29 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "INFO | 13:41:50 | Initializing Callbacks\n", - "INFO | 13:41:50 | Initializing Loss Function\n", - "INFO | 13:41:50 | Initializing Metrics\n", - "INFO | 13:41:50 | Running Input Pipeline\n", - "INFO | 13:41:50 | Read data file project/benzene_mod.xyz\n", - "INFO | 13:41:50 | Loading data from project/benzene_mod.xyz\n", - "INFO | 13:42:00 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12919.46it/s]\n", - "INFO | 13:42:00 | Computing per element energy regression.\n", - "INFO | 13:42:06 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12653.65it/s]\n", - "INFO | 13:42:07 | Initializing Model\n", - "INFO | 13:42:08 | initializing 1 models\n", - "INFO | 13:42:13 | Initializing Optimizer\n", - "INFO | 13:42:13 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" + "INFO | 13:18:06 | Initializing Callbacks\n", + "INFO | 13:18:06 | Initializing Loss Function\n", + "INFO | 13:18:06 | Initializing Metrics\n", + "INFO | 13:18:06 | Running Input Pipeline\n", + "INFO | 13:18:06 | Read data file project/benzene_mod.xyz\n", + "INFO | 13:18:06 | Loading data from project/benzene_mod.xyz\n", + "INFO | 13:18:16 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12775.52it/s]\n", + "INFO | 13:18:16 | Computing per element energy regression.\n", + "INFO | 13:18:22 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12708.86it/s]\n", + "INFO | 13:18:23 | Initializing Model\n", + "INFO | 13:18:24 | initializing 1 models\n", + "INFO | 13:18:29 | Initializing Optimizer\n", + "INFO | 13:18:29 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" ] } ], @@ -292,16 +294,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9771.12it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 13090.43it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12596.15it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10840.52it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:37<00:00, 2.18s/it, val_loss=0.31]\n" ] } ], @@ -330,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -401,15 +403,15 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 280.00it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.29it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 292.45it/s]\n", + "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.67it/s, test_loss=0.06859629925320611]\n" ] } ], @@ -421,23 +423,15 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5706.54it/s]\n", - "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.48it/s, test_loss=0.5443810628577777]\n" + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5692.60it/s]\n", + "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.41it/s, test_loss=0.5443810628577777]\n" ] } ], @@ -445,6 +439,63 @@ "!apax eval config.yaml --n-data 10" ] }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "could not convert string to float: 'NA'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[16], line 20\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m idx, value \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(row):\n\u001b[1;32m 19\u001b[0m key \u001b[38;5;241m=\u001b[39m headers[idx]\n\u001b[0;32m---> 20\u001b[0m data_dict[key]\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;28mfloat\u001b[39m(value))\n\u001b[1;32m 22\u001b[0m fig, axes \u001b[38;5;241m=\u001b[39m plt\u001b[38;5;241m.\u001b[39msubplots(\u001b[38;5;241m2\u001b[39m, \u001b[38;5;241m2\u001b[39m, constrained_layout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 23\u001b[0m axes \u001b[38;5;241m=\u001b[39m axes\u001b[38;5;241m.\u001b[39mravel()\n", + "\u001b[0;31mValueError\u001b[0m: could not convert string to float: 'NA'" + ] + } + ], + "source": [ + "path = \"project/models/benzene_dft_script/eval/log.csv\"\n", + "\n", + "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", + "data_dict = {}\n", + "\n", + "with open(path, 'r') as file:\n", + " reader = csv.reader(file)\n", + "\n", + " # Extract the headers (keys) from the first row\n", + " headers = next(reader)\n", + "\n", + " # Initialize empty lists for each key\n", + " for header in headers:\n", + " data_dict[header] = []\n", + "\n", + " # Read the rest of the rows and append values to the corresponding key\n", + " for row in reader:\n", + " for idx, value in enumerate(row):\n", + " key = headers[idx]\n", + " data_dict[key].append(float(value))\n", + "\n", + "fig, axes = plt.subplots(2, 2, constrained_layout=True)\n", + "axes = axes.ravel()\n", + "fig.suptitle(f'Metrics', fontsize=16)\n", + "\n", + "for id, key in enumerate(keys):\n", + " val = np.array(data_dict[f\"val_{key}\"])\n", + " train = np.array(data_dict[f\"train_{key}\"])\n", + " epoch = np.array(data_dict[\"epoch\"])\n", + "\n", + " axes[id].plot(epoch, val, label=\"val data\")\n", + " axes[id].plot(epoch, train, label=\"train data\")\n", + "\n", + " axes[id].set_ylabel(f\"{key}\")\n", + " axes[id].set_xlabel(r\"epoch\")\n", + "\n", + "plt.show()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -532,6 +583,253 @@ "| reset_layers | [] | List of layers to reinitialize parameters. |\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", + "\n", + "- **n_epochs**: ``\n", + " - Number of training epochs.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **seed**: 1\n", + " - Seed for initializing random numbers.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **patience**: None\n", + " - Number of epochs without improvement before training termination.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_models**: 1\n", + " - Number of models trained simultaneously.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_jitted_steps**: 1\n", + " - Number of train batches in a compiled loop. Can speed up for small batches." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Data**\n", + " - directory: models/\n", + " - Path to directory where training results and checkpoints are written.\n", + "\n", + " - experiment: apax\n", + " - Model name distinguishing from others in directory.\n", + "\n", + " - data_path: ``\n", + " - Path to single dataset file.\n", + "\n", + " - train_data_path: ``\n", + " - Path to training dataset.\n", + "\n", + " - val_data_path: ``\n", + " - Path to validation dataset.\n", + "\n", + " - test_data_path: ``\n", + " - Path to test dataset.\n", + "\n", + " - n_train: 1000\n", + " - Number of training data points.\n", + " \n", + " - n_valid: 100\n", + " - Number of validation data points.\n", + " \n", + " - batch_size: 32\n", + " - Number of training examples evaluated at once.\n", + " \n", + " - valid_batch_size: 100\n", + " - Number of validation examples evaluated at once.\n", + " \n", + " - shift_method: \"per_element_regression_shift\"\n", + " - Method for shifting.\n", + " \n", + " - shift_options: energy_regularization: 1.0\n", + " - Regularization magnitude for energy regression.\n", + " \n", + " - shuffle_buffer_size: 1000\n", + " - Size of `tf.data` shuffle buffer.\n", + " \n", + " - pos_unit: Ang\n", + " - Positional unit.\n", + " \n", + " - energy_unit: eV\n", + " - Energy unit.\n", + " \n", + " - additional_properties_info:\n", + " - Dictionary of property name, shape pairs.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Model**\n", + " - n_basis: 7\n", + " - Number of Gaussian basis functions.\n", + "\n", + " - n_radial: 5\n", + " - Number of contracted basis functions.\n", + "\n", + " - nn: [512, 512]\n", + " - Hidden layers and units.\n", + "\n", + " - r_max: 6.0\n", + " - Maximum position of first basis function's mean.\n", + "\n", + " - r_min: 0.5\n", + " - Descriptor cutoff radius.\n", + "\n", + " - use_zbl: false\n", + " - Use emperical Ziegler-Biersack-Littmark potential.\n", + "\n", + " - b_init: normal\n", + " - Initialization scheme for biases.\n", + "\n", + " - descriptor_dtype: fp64\n", + " - Descriptor data type.\n", + "\n", + " - readout_dtype: fp32\n", + " - Readout data type.\n", + "\n", + " - scale_shift_dtype: fp32\n", + " - Scale/Shift data type.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Loss**\n", + " - loss_type: structures\n", + " - Weighting scheme for atomic contributions.\n", + "\n", + " - name: energy\n", + " - Quantity keyword.\n", + "\n", + " - weight: 1.0\n", + " - Weighting factor in loss function.\n", + "\n", + " - name: forces\n", + " - Quantity keyword.\n", + "\n", + " - weight: 4.0\n", + " - Weighting factor in loss function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Metrics**\n", + " - name: energy\n", + " - Quantity keyword.\n", + " \n", + " - reductions:\n", + " - List of reductions on target-prediction differences.\n", + " \n", + " - name: forces\n", + " - Quantity keyword.\n", + " \n", + " - reductions: mae, mse\n", + " - Reductions on target-prediction differences.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Optimizer**\n", + " - opt_name: adam\n", + " - Optimizer name.\n", + " \n", + " - opt_kwargs: {}\n", + " - Optimizer keyword arguments.\n", + " \n", + " - emb_lr: 0.03\n", + " - Learning rate for elemental embedding contraction coefficients.\n", + " \n", + " - nn_lr: 0.03\n", + " - Learning rate for neural network parameters.\n", + " \n", + " - scale_lr: 0.001\n", + " - Learning rate for elemental output scaling factors.\n", + " \n", + " - shift_lr: 0.05\n", + " - Learning rate for elemental output shifts.\n", + " \n", + " - zbl_lr: 0.001\n", + " - Learning rate for Zero-Body-Loss.\n", + " \n", + " - transition_begin: 0\n", + " - Training steps before linear learning rate schedule.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Callbacks**\n", + " - name: csv\n", + " - Callback name.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Progress Bar**\n", + " - disable_epoch_pbar: false\n", + " - Disable epoch progress bar.\n", + "\n", + " - disable_nl_pbar: false\n", + " - Disable NL precomputation progress bar.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Checkpoints**\n", + " - ckpt_interval: 1\n", + " - Epochs between checkpoints.\n", + " \n", + " - base_model_checkpoint: null\n", + " - Path to pre-trained model checkpoint.\n", + " \n", + " - reset_layers: []\n", + " - List of layers to reinitialize parameters." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -541,11 +839,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ - "!rm -r project config.yaml error_config.yaml eval.log" + "# !rm -r project config.yaml error_config.yaml eval.log" ] } ], diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index 1264c277..75b8dc63 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -1,5 +1,15 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter('ignore')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -7,7 +17,7 @@ "# Molecular Dynamics\n", "\n", "In this tutorial we will cover how to use trained models to drive MD simulations.\n", - "For this purpose, apax offers two options: ASE and JaxMD.\n", + "For this purpose, apax offers two options: ASE and JaxMD. Keep in mind that JaxMD can be GPU/TPU accelerated and is therefore much faster.\n", "Both will be covered below." ] }, @@ -18,7 +28,72 @@ "## Basic Model Training\n", "\n", "First we need to train a model.\n", - "If you have the parameters from tutorial 01, you can point the paths to those models and skip the current section." + "If you have the parameters from tutorial 01, you can point the paths to those models and skip the current section to the [ASE MD](##-The-ASE-calculator) or the [JaxMD](##-JaxMD) section." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "!apax template train # generating the config file in the cwd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12924.12it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11632.43it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:36<00:00, 2.17s/it, val_loss=0.31]\n" + ] + } + ], + "source": [ + "from pathlib import Path\n", + "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets\n", + "from apax.train.run import run\n", + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "# Download and modify the dataset\n", + "data_path = Path(\"project\")\n", + "experiment = \"benzene_md\"\n", + "\n", + "file_path = download_benzene_DFT(data_path)\n", + "file_path = mod_md_datasets(file_path)\n", + "\n", + "\n", + "# Modify the config file (can be done manually)\n", + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"experiment\": experiment,\n", + " \"directory\": str(data_path / \"models\"),\n", + " \"data_path\": str(file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "\n", + "# dump config for cli showcase\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)\n", + "\n", + "\n", + "# Train model\n", + "run(config_dict)\n" ] }, { @@ -29,11 +104,47 @@ "\n", "If you require some ASE features during your simulation, we provide an alternative to the JaxMD interface.\n", "\n", - "An ASE calculator of a trained model can be instantiated as follows\n", + "Please refer to the [ASE documentation](https://wiki.fysik.dtu.dk/ase/ase/calculators/calculators.html) to see how to use ASE calculators.\n", + "\n", + "An ASE calculator of a trained model can be instantiated as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from ase.io import read\n", + "from apax.md import ASECalculator\n", + "from ase.md.langevin import Langevin\n", + "from ase import units\n", + "import numpy as np\n", + "from ase.io.trajectory import Trajectory\n", + "\n", + "\n", + "# read starting structure and define modelpath\n", + "atoms = read(file_path, index=0)\n", + "model_dir = data_path / f\"models/{experiment}\"\n", + "\n", + "\n", + "# initiolize the apax ase calculator and assign it to the starting structure\n", + "calc = ASECalculator(model_dir=model_dir)\n", + "atoms.calc = calc\n", + "\n", "\n", - "CODE\n", + "# perform MD simulation\n", + "dyn = Langevin(\n", + " atoms=atoms,\n", + " timestep=0.5 * units.fs,\n", + " temperature_K=300,\n", + " friction=0.01 / units.fs,\n", + ")\n", "\n", - "Please refer to the ASE documentation LINK to see how to use ASE calculators." + "traj = Trajectory('example.traj', 'w', atoms)\n", + "dyn.attach(traj.write, interval=100)\n", + "dyn.run(1000)\n", + "traj.close()" ] }, { @@ -43,8 +154,8 @@ "## JaxMD\n", "\n", "While the ASE interface is convenient and flexible, it is not meant for high performance applications.\n", - "For these purposes, apax comes with an interface to JaxMD.\n", - "JaxMD LINK is a high performance molecular dynamics engine built on top of Jax LINK.\n", + "For these purposes, apax comes with an interface to [JaxMD](https://jax-md.readthedocs.io/en/main/#).\n", + "JaxMD is a high performance molecular dynamics engine built on top of [Jax](https://jax.readthedocs.io/en/latest/index.html).\n", "The CLI provides easy access to standard NVT and NPT simulations.\n", "More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). \n", "Trained apax models can of course be used as `energy_fn` in such custom simulations.\n", @@ -56,31 +167,128 @@ "metadata": {}, "source": [ "### Configuration\n", - "We can once again use the template command to give ourselves a quickstart.\n", - "\n", - "`apax template md --minimal`\n", + "We can once again use the template command to give ourselves a quickstart.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "!apax template md" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "Open the config and specify the starting structure and simulation parameters.\n", "If you specify the data set file itself, the first structure of the data set is going to be used as the initial structure.\n", "Your `md_config_minimal.yaml` should look similar to this:\n", "\n", "```yaml\n", + "ensemble:\n", + " temperature: 300 # K\n", + " \n", "duration: 20_000 # fs\n", - "initial_structure: md17.extxyz\n", - "```\n", + "initial_structure: project/benzene_mod.xyz\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "config_path = Path(\"md_config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"initial_structure\": str(file_path), # if the model from example 01 is used change this\n", + " \"duration\": 1000, #fs\n", + " \"ensemble\": {\n", + " \"temperature\": 300,\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"md_config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "As with training configurations, we can use the `validate` command to ensure our input is valid before we submit the calculation.\n" ] }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "md_config.yaml is a valid MD config.\n" + ] + } + ], + "source": [ + "!apax validate md md_config.yaml" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the simulation\n", "\n", - "The simulation can be started by running\n", + "The simulation can be started by running" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 12:39:38 | reading structure\n", + "INFO | 12:39:39 | Unable to initialize backend 'cuda': \n", + "INFO | 12:39:39 | Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n", + "INFO | 12:39:39 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", + "INFO | 12:39:39 | initializing model\n", + "INFO | 12:39:39 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/benzene_md/best\n", + "INFO | 12:39:39 | Initializing new trajectory file at md/md.h5\n", + "INFO | 12:39:39 | initializing simulation\n", + "INFO | 12:39:41 | running simulation for 1.0 ps\n", + "Simulation: 100%|███████████████████████████████████| 2000/2000 [00:10<00:00, 183.72it/s, T=196.3 K]\n", + "INFO | 12:39:52 | simulation finished after elapsed time: 10.93 s\n" + ] + } + ], + "source": [ + "!apax md config.yaml md_config.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "`apax md config.yaml md_config_minimal.yaml`\n", "\n", "where `config.yaml` is the configuration file that was used to train the model.\n", "\n", @@ -98,6 +306,29 @@ "TODO" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To remove all the created files and clean up yor working directory run" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!rm -r project md config.yaml example.traj md_config.yaml" + ] + }, { "cell_type": "code", "execution_count": null, @@ -107,8 +338,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "apax", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" } }, "nbformat": 4, From 4167945ce33815d7d8afbf1985c9995522d4ad73 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 17:13:39 +0100 Subject: [PATCH 088/192] ApaxCSVLogger on_test_batch_begin() hook --- apax/train/callbacks.py | 50 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 460cad04..6880f81f 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -2,17 +2,65 @@ import tensorflow as tf from keras.callbacks import CSVLogger, TensorBoard +import numpy as np +import collections +import csv log = logging.getLogger(__name__) +class CSVLoggerApax(CSVLogger): + def __init__(self, filename, separator=",", append=False): + super().__init__(filename, separator=",", append=False) + + def on_test_batch_begin(self, batch, logs=None): + logs = logs or {} + + def handle_value(k): + is_zero_dim_ndarray = isinstance(k, np.ndarray) and k.ndim == 0 + if isinstance(k, str): + return k + elif ( + isinstance(k, collections.abc.Iterable) + and not is_zero_dim_ndarray + ): + return f"\"[{', '.join(map(str, k))}]\"" + else: + return k + + if self.keys is None: + self.keys = sorted(logs.keys()) + # When validation_freq > 1, `val_` keys are not in first epoch logs + # Add the `val_` keys so that its part of the fieldnames of writer. + + if not self.writer: + + class CustomDialect(csv.excel): + delimiter = self.sep + + fieldnames = ["batch"] + self.keys + + self.writer = csv.DictWriter( + self.csv_file, fieldnames=fieldnames, dialect=CustomDialect + ) + if self.append_header: + self.writer.writeheader() + + row_dict = collections.OrderedDict({"batch": batch}) + row_dict.update( + (key, handle_value(logs.get(key, "NA"))) for key in self.keys + ) + self.writer.writerow(row_dict) + self.csv_file.flush() + + def initialize_callbacks(callback_configs, model_version_path): log.info("Initializing Callbacks") dummy_model = tf.keras.Model() callback_dict = { "csv": { - "class": CSVLogger, + "class": CSVLoggerApax, "log_path": model_version_path / "log.csv", "path_arg_name": "filename", "kwargs": {"append": True}, From 62dab0e26ac4cf6a0610d16e5615c742ed33b5b7 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 17:13:54 +0100 Subject: [PATCH 089/192] eval fix --- apax/train/eval.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/apax/train/eval.py b/apax/train/eval.py index 67ce1dda..86a408f6 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -72,39 +72,31 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal loss_fn, Metrics, model=model, sam_rho=0.0, is_ensemble=is_ensemble ) - test_steps_per_epoch = test_ds.steps_per_epoch() - batch_test_ds = test_ds.shuffle_and_batch() + batch_test_ds = test_ds.batch() - epoch_loss = {} - epoch_start_time = time.time() - - epoch_loss.update({"test_loss": 0.0}) test_metrics = Metrics.empty() batch_pbar = trange( - 0, test_steps_per_epoch, desc="Batches", ncols=100, disable=False, leave=True + 0, test_ds.n_data, desc="Structure", ncols=100, disable=False, leave=True ) - for batch_idx in range(test_steps_per_epoch): + for batch_idx in range(test_ds.n_data): batch = next(batch_test_ds) + batch_start_time = time.time() batch_loss, test_metrics = test_step_fn(params, batch, test_metrics) + batch_metrics = {"test_loss": float(batch_loss)} + batch_metrics.update({ + f"test_{key}": float(val) for key, val in test_metrics.compute().items() + }) + batch_end_time = time.time() + batch_metrics.update({"time": batch_end_time - batch_start_time}) + + callbacks.on_test_batch_begin(batch=batch_idx, logs=batch_metrics) - epoch_loss["test_loss"] += batch_loss - batch_pbar.set_postfix(test_loss=epoch_loss["test_loss"] / batch_idx) + batch_pbar.set_postfix(test_loss=batch_metrics["test_loss"]) batch_pbar.update() batch_pbar.close() - - epoch_loss["test_loss"] /= test_steps_per_epoch - epoch_loss["test_loss"] = float(epoch_loss["test_loss"]) - epoch_metrics = { - f"test_{key}": float(val) for key, val in test_metrics.compute().items() - } - epoch_metrics.update({**epoch_loss}) - epoch_end_time = time.time() - epoch_metrics.update({"epoch_time": epoch_end_time - epoch_start_time}) - callbacks.on_epoch_end(epoch=1, logs=epoch_metrics) callbacks.on_train_end() - # TODO currently this has no informative output def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): From 038c55b66cbfc5bc47f49fb97265779f6e3e09ec Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 17:30:55 +0100 Subject: [PATCH 090/192] linting --- apax/train/callbacks.py | 15 +++++---------- apax/train/eval.py | 8 ++++---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 6880f81f..07ba69c0 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -1,10 +1,10 @@ +import collections +import csv import logging +import numpy as np import tensorflow as tf from keras.callbacks import CSVLogger, TensorBoard -import numpy as np -import collections -import csv log = logging.getLogger(__name__) @@ -20,10 +20,7 @@ def handle_value(k): is_zero_dim_ndarray = isinstance(k, np.ndarray) and k.ndim == 0 if isinstance(k, str): return k - elif ( - isinstance(k, collections.abc.Iterable) - and not is_zero_dim_ndarray - ): + elif isinstance(k, collections.abc.Iterable) and not is_zero_dim_ndarray: return f"\"[{', '.join(map(str, k))}]\"" else: return k @@ -47,9 +44,7 @@ class CustomDialect(csv.excel): self.writer.writeheader() row_dict = collections.OrderedDict({"batch": batch}) - row_dict.update( - (key, handle_value(logs.get(key, "NA"))) for key in self.keys - ) + row_dict.update((key, handle_value(logs.get(key, "NA"))) for key in self.keys) self.writer.writerow(row_dict) self.csv_file.flush() diff --git a/apax/train/eval.py b/apax/train/eval.py index 86a408f6..af57afb9 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -85,9 +85,9 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal batch_loss, test_metrics = test_step_fn(params, batch, test_metrics) batch_metrics = {"test_loss": float(batch_loss)} - batch_metrics.update({ - f"test_{key}": float(val) for key, val in test_metrics.compute().items() - }) + batch_metrics.update( + {f"test_{key}": float(val) for key, val in test_metrics.compute().items()} + ) batch_end_time = time.time() batch_metrics.update({"time": batch_end_time - batch_start_time}) @@ -116,7 +116,7 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): raw_ds = load_test_data(config, model_version_path, eval_path, n_test) test_ds = initialize_dataset(config, raw_ds, read_labels=True, calc_stats=False) - test_ds.set_batch_size(1) # TODO temporary + test_ds.set_batch_size(1) _, init_box = test_ds.init_input() From d5190ae7d2a9a102970e97959ac64f12448e9c63 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 17:39:06 +0100 Subject: [PATCH 091/192] added eval to 01 docs --- examples/01_Model_Training.ipynb | 89 +++++++++++++++----------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 5e7ff30a..ca0f1469 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -248,22 +248,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "INFO | 13:18:06 | Initializing Callbacks\n", - "INFO | 13:18:06 | Initializing Loss Function\n", - "INFO | 13:18:06 | Initializing Metrics\n", - "INFO | 13:18:06 | Running Input Pipeline\n", - "INFO | 13:18:06 | Read data file project/benzene_mod.xyz\n", - "INFO | 13:18:06 | Loading data from project/benzene_mod.xyz\n", - "INFO | 13:18:16 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12775.52it/s]\n", - "INFO | 13:18:16 | Computing per element energy regression.\n", - "INFO | 13:18:22 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12708.86it/s]\n", - "INFO | 13:18:23 | Initializing Model\n", - "INFO | 13:18:24 | initializing 1 models\n", - "INFO | 13:18:29 | Initializing Optimizer\n", - "INFO | 13:18:29 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.76s/it, val_loss=0.63]\n" + "INFO | 17:12:25 | Initializing Callbacks\n", + "INFO | 17:12:25 | Initializing Loss Function\n", + "INFO | 17:12:25 | Initializing Metrics\n", + "INFO | 17:12:25 | Running Input Pipeline\n", + "INFO | 17:12:25 | Read data file project/benzene_mod.xyz\n", + "INFO | 17:12:25 | Loading data from project/benzene_mod.xyz\n", + "INFO | 17:12:36 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12876.51it/s]\n", + "INFO | 17:12:36 | Computing per element energy regression.\n", + "INFO | 17:12:42 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12902.77it/s]\n", + "INFO | 17:12:43 | Initializing Model\n", + "INFO | 17:12:43 | initializing 1 models\n", + "INFO | 17:12:49 | Initializing Optimizer\n", + "INFO | 17:12:49 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.77s/it, val_loss=0.63]\n" ] } ], @@ -301,9 +301,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12596.15it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 10840.52it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:37<00:00, 2.18s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11830.34it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11579.76it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" ] } ], @@ -403,57 +403,56 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 292.45it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.67it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 11736.50it/s]\n", + "Structure: 100%|█████████████████████████████| 5000/5000 [00:21<00:00, 232.32it/s, test_loss=0.0211]\n" ] } ], "source": [ "from apax.train.eval import eval_model\n", "\n", - "eval_model(config_dict, n_test=10)" + "eval_model(config_dict, n_test=5000)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5692.60it/s]\n", - "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.41it/s, test_loss=0.5443810628577777]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 12105.28it/s]\n", + "Structure: 100%|██████████████████████████████| 5000/5000 [00:17<00:00, 288.77it/s, test_loss=0.181]\n" ] } ], "source": [ - "!apax eval config.yaml --n-data 10" + "!apax eval config.yaml --n-data 5000" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 24, "metadata": {}, "outputs": [ { - "ename": "ValueError", - "evalue": "could not convert string to float: 'NA'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[16], line 20\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m idx, value \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(row):\n\u001b[1;32m 19\u001b[0m key \u001b[38;5;241m=\u001b[39m headers[idx]\n\u001b[0;32m---> 20\u001b[0m data_dict[key]\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;28mfloat\u001b[39m(value))\n\u001b[1;32m 22\u001b[0m fig, axes \u001b[38;5;241m=\u001b[39m plt\u001b[38;5;241m.\u001b[39msubplots(\u001b[38;5;241m2\u001b[39m, \u001b[38;5;241m2\u001b[39m, constrained_layout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 23\u001b[0m axes \u001b[38;5;241m=\u001b[39m axes\u001b[38;5;241m.\u001b[39mravel()\n", - "\u001b[0;31mValueError\u001b[0m: could not convert string to float: 'NA'" - ] + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -478,21 +477,15 @@ " key = headers[idx]\n", " data_dict[key].append(float(value))\n", "\n", - "fig, axes = plt.subplots(2, 2, constrained_layout=True)\n", + "fig, axes = plt.subplots(1, 4, constrained_layout=True)\n", "axes = axes.ravel()\n", "fig.suptitle(f'Metrics', fontsize=16)\n", "\n", "for id, key in enumerate(keys):\n", - " val = np.array(data_dict[f\"val_{key}\"])\n", - " train = np.array(data_dict[f\"train_{key}\"])\n", - " epoch = np.array(data_dict[\"epoch\"])\n", - "\n", - " axes[id].plot(epoch, val, label=\"val data\")\n", - " axes[id].plot(epoch, train, label=\"train data\")\n", - "\n", - " axes[id].set_ylabel(f\"{key}\")\n", - " axes[id].set_xlabel(r\"epoch\")\n", + " test = np.array(data_dict[f\"test_{key}\"])\n", "\n", + " axes[id].set_title(f'{key}')\n", + " axes[id].boxplot(test)\n", "plt.show()" ] }, @@ -839,7 +832,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ From 863130e1cee42535be15cdc0c47d30979b9e5533 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:09:08 +0000 Subject: [PATCH 092/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/eval.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/train/eval.py b/apax/train/eval.py index ab6a1577..67ce1dda 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -145,4 +145,4 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): test_ds, callbacks, is_ensemble=config.n_models > 1, - ) \ No newline at end of file + ) From 70423bd64d504d627f88d01c1aa8b872e823685e Mon Sep 17 00:00:00 2001 From: Nico Segreto Date: Wed, 6 Mar 2024 18:20:54 +0100 Subject: [PATCH 093/192] Moredocs nico (#240) * Model training example * added eval to 01 docs --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- apax/config/md_config.py | 2 +- examples/01_Model_Training.ipynb | 399 +++++++++++++++++++++++---- examples/02_Molecular_Dynamics.ipynb | 275 +++++++++++++++++- 3 files changed, 606 insertions(+), 70 deletions(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index f34a1889..989b04ea 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -60,7 +60,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. - intitial_structure: + initial_structure: Path to the starting structure of the simulation. sim_dir: Directory where simulation file will be stored. diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 66b8d9be..ca0f1469 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -1,5 +1,15 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter('ignore')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -16,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -44,17 +54,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -100,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -132,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -168,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -194,7 +196,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -209,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -239,29 +241,29 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "INFO | 13:41:50 | Initializing Callbacks\n", - "INFO | 13:41:50 | Initializing Loss Function\n", - "INFO | 13:41:50 | Initializing Metrics\n", - "INFO | 13:41:50 | Running Input Pipeline\n", - "INFO | 13:41:50 | Read data file project/benzene_mod.xyz\n", - "INFO | 13:41:50 | Loading data from project/benzene_mod.xyz\n", - "INFO | 13:42:00 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12919.46it/s]\n", - "INFO | 13:42:00 | Computing per element energy regression.\n", - "INFO | 13:42:06 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12653.65it/s]\n", - "INFO | 13:42:07 | Initializing Model\n", - "INFO | 13:42:08 | initializing 1 models\n", - "INFO | 13:42:13 | Initializing Optimizer\n", - "INFO | 13:42:13 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:28<00:00, 2.82s/it, val_loss=0.63]\n" + "INFO | 17:12:25 | Initializing Callbacks\n", + "INFO | 17:12:25 | Initializing Loss Function\n", + "INFO | 17:12:25 | Initializing Metrics\n", + "INFO | 17:12:25 | Running Input Pipeline\n", + "INFO | 17:12:25 | Read data file project/benzene_mod.xyz\n", + "INFO | 17:12:25 | Loading data from project/benzene_mod.xyz\n", + "INFO | 17:12:36 | Precomputing neighborlists\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12876.51it/s]\n", + "INFO | 17:12:36 | Computing per element energy regression.\n", + "INFO | 17:12:42 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12902.77it/s]\n", + "INFO | 17:12:43 | Initializing Model\n", + "INFO | 17:12:43 | initializing 1 models\n", + "INFO | 17:12:49 | Initializing Optimizer\n", + "INFO | 17:12:49 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.77s/it, val_loss=0.63]\n" ] } ], @@ -292,15 +294,15 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████| 1000/1000 [00:00<00:00, 9771.12it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 13090.43it/s]\n", + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11830.34it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11579.76it/s]\n", "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" ] } @@ -330,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -401,48 +403,90 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████████| 10/10 [00:00<00:00, 280.00it/s]\n", - "Batches: 100%|███████████████████████| 10/10 [00:01<00:00, 6.29it/s, test_loss=0.06859629925320611]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 11736.50it/s]\n", + "Structure: 100%|█████████████████████████████| 5000/5000 [00:21<00:00, 232.32it/s, test_loss=0.0211]\n" ] } ], "source": [ "from apax.train.eval import eval_model\n", "\n", - "eval_model(config_dict, n_test=10)" + "eval_model(config_dict, n_test=5000)" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 16, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/linux3_i1/segreto/miniconda3/envs/apax/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", - " pid, fd = os.forkpty()\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 5706.54it/s]\n", - "Batches: 100%|████████████████████████| 10/10 [00:01<00:00, 6.48it/s, test_loss=0.5443810628577777]\n" + "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 12105.28it/s]\n", + "Structure: 100%|██████████████████████████████| 5000/5000 [00:17<00:00, 288.77it/s, test_loss=0.181]\n" ] } ], "source": [ - "!apax eval config.yaml --n-data 10" + "!apax eval config.yaml --n-data 5000" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "path = \"project/models/benzene_dft_script/eval/log.csv\"\n", + "\n", + "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", + "data_dict = {}\n", + "\n", + "with open(path, 'r') as file:\n", + " reader = csv.reader(file)\n", + "\n", + " # Extract the headers (keys) from the first row\n", + " headers = next(reader)\n", + "\n", + " # Initialize empty lists for each key\n", + " for header in headers:\n", + " data_dict[header] = []\n", + "\n", + " # Read the rest of the rows and append values to the corresponding key\n", + " for row in reader:\n", + " for idx, value in enumerate(row):\n", + " key = headers[idx]\n", + " data_dict[key].append(float(value))\n", + "\n", + "fig, axes = plt.subplots(1, 4, constrained_layout=True)\n", + "axes = axes.ravel()\n", + "fig.suptitle(f'Metrics', fontsize=16)\n", + "\n", + "for id, key in enumerate(keys):\n", + " test = np.array(data_dict[f\"test_{key}\"])\n", + "\n", + " axes[id].set_title(f'{key}')\n", + " axes[id].boxplot(test)\n", + "plt.show()" ] }, { @@ -532,6 +576,253 @@ "| reset_layers | [] | List of layers to reinitialize parameters. |\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", + "\n", + "- **n_epochs**: ``\n", + " - Number of training epochs.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **seed**: 1\n", + " - Seed for initializing random numbers.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **patience**: None\n", + " - Number of epochs without improvement before training termination.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_models**: 1\n", + " - Number of models trained simultaneously.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_jitted_steps**: 1\n", + " - Number of train batches in a compiled loop. Can speed up for small batches." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Data**\n", + " - directory: models/\n", + " - Path to directory where training results and checkpoints are written.\n", + "\n", + " - experiment: apax\n", + " - Model name distinguishing from others in directory.\n", + "\n", + " - data_path: ``\n", + " - Path to single dataset file.\n", + "\n", + " - train_data_path: ``\n", + " - Path to training dataset.\n", + "\n", + " - val_data_path: ``\n", + " - Path to validation dataset.\n", + "\n", + " - test_data_path: ``\n", + " - Path to test dataset.\n", + "\n", + " - n_train: 1000\n", + " - Number of training data points.\n", + " \n", + " - n_valid: 100\n", + " - Number of validation data points.\n", + " \n", + " - batch_size: 32\n", + " - Number of training examples evaluated at once.\n", + " \n", + " - valid_batch_size: 100\n", + " - Number of validation examples evaluated at once.\n", + " \n", + " - shift_method: \"per_element_regression_shift\"\n", + " - Method for shifting.\n", + " \n", + " - shift_options: energy_regularization: 1.0\n", + " - Regularization magnitude for energy regression.\n", + " \n", + " - shuffle_buffer_size: 1000\n", + " - Size of `tf.data` shuffle buffer.\n", + " \n", + " - pos_unit: Ang\n", + " - Positional unit.\n", + " \n", + " - energy_unit: eV\n", + " - Energy unit.\n", + " \n", + " - additional_properties_info:\n", + " - Dictionary of property name, shape pairs.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Model**\n", + " - n_basis: 7\n", + " - Number of Gaussian basis functions.\n", + "\n", + " - n_radial: 5\n", + " - Number of contracted basis functions.\n", + "\n", + " - nn: [512, 512]\n", + " - Hidden layers and units.\n", + "\n", + " - r_max: 6.0\n", + " - Maximum position of first basis function's mean.\n", + "\n", + " - r_min: 0.5\n", + " - Descriptor cutoff radius.\n", + "\n", + " - use_zbl: false\n", + " - Use emperical Ziegler-Biersack-Littmark potential.\n", + "\n", + " - b_init: normal\n", + " - Initialization scheme for biases.\n", + "\n", + " - descriptor_dtype: fp64\n", + " - Descriptor data type.\n", + "\n", + " - readout_dtype: fp32\n", + " - Readout data type.\n", + "\n", + " - scale_shift_dtype: fp32\n", + " - Scale/Shift data type.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Loss**\n", + " - loss_type: structures\n", + " - Weighting scheme for atomic contributions.\n", + "\n", + " - name: energy\n", + " - Quantity keyword.\n", + "\n", + " - weight: 1.0\n", + " - Weighting factor in loss function.\n", + "\n", + " - name: forces\n", + " - Quantity keyword.\n", + "\n", + " - weight: 4.0\n", + " - Weighting factor in loss function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Metrics**\n", + " - name: energy\n", + " - Quantity keyword.\n", + " \n", + " - reductions:\n", + " - List of reductions on target-prediction differences.\n", + " \n", + " - name: forces\n", + " - Quantity keyword.\n", + " \n", + " - reductions: mae, mse\n", + " - Reductions on target-prediction differences.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Optimizer**\n", + " - opt_name: adam\n", + " - Optimizer name.\n", + " \n", + " - opt_kwargs: {}\n", + " - Optimizer keyword arguments.\n", + " \n", + " - emb_lr: 0.03\n", + " - Learning rate for elemental embedding contraction coefficients.\n", + " \n", + " - nn_lr: 0.03\n", + " - Learning rate for neural network parameters.\n", + " \n", + " - scale_lr: 0.001\n", + " - Learning rate for elemental output scaling factors.\n", + " \n", + " - shift_lr: 0.05\n", + " - Learning rate for elemental output shifts.\n", + " \n", + " - zbl_lr: 0.001\n", + " - Learning rate for Zero-Body-Loss.\n", + " \n", + " - transition_begin: 0\n", + " - Training steps before linear learning rate schedule.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Callbacks**\n", + " - name: csv\n", + " - Callback name.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Progress Bar**\n", + " - disable_epoch_pbar: false\n", + " - Disable epoch progress bar.\n", + "\n", + " - disable_nl_pbar: false\n", + " - Disable NL precomputation progress bar.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Checkpoints**\n", + " - ckpt_interval: 1\n", + " - Epochs between checkpoints.\n", + " \n", + " - base_model_checkpoint: null\n", + " - Path to pre-trained model checkpoint.\n", + " \n", + " - reset_layers: []\n", + " - List of layers to reinitialize parameters." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -541,11 +832,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ - "!rm -r project config.yaml error_config.yaml eval.log" + "# !rm -r project config.yaml error_config.yaml eval.log" ] } ], diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index 1264c277..75b8dc63 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -1,5 +1,15 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter('ignore')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -7,7 +17,7 @@ "# Molecular Dynamics\n", "\n", "In this tutorial we will cover how to use trained models to drive MD simulations.\n", - "For this purpose, apax offers two options: ASE and JaxMD.\n", + "For this purpose, apax offers two options: ASE and JaxMD. Keep in mind that JaxMD can be GPU/TPU accelerated and is therefore much faster.\n", "Both will be covered below." ] }, @@ -18,7 +28,72 @@ "## Basic Model Training\n", "\n", "First we need to train a model.\n", - "If you have the parameters from tutorial 01, you can point the paths to those models and skip the current section." + "If you have the parameters from tutorial 01, you can point the paths to those models and skip the current section to the [ASE MD](##-The-ASE-calculator) or the [JaxMD](##-JaxMD) section." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "!apax template train # generating the config file in the cwd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12924.12it/s]\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11632.43it/s]\n", + "Epochs: 100%|██████████████████████████████████████| 100/100 [03:36<00:00, 2.17s/it, val_loss=0.31]\n" + ] + } + ], + "source": [ + "from pathlib import Path\n", + "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets\n", + "from apax.train.run import run\n", + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "# Download and modify the dataset\n", + "data_path = Path(\"project\")\n", + "experiment = \"benzene_md\"\n", + "\n", + "file_path = download_benzene_DFT(data_path)\n", + "file_path = mod_md_datasets(file_path)\n", + "\n", + "\n", + "# Modify the config file (can be done manually)\n", + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"experiment\": experiment,\n", + " \"directory\": str(data_path / \"models\"),\n", + " \"data_path\": str(file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "\n", + "# dump config for cli showcase\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)\n", + "\n", + "\n", + "# Train model\n", + "run(config_dict)\n" ] }, { @@ -29,11 +104,47 @@ "\n", "If you require some ASE features during your simulation, we provide an alternative to the JaxMD interface.\n", "\n", - "An ASE calculator of a trained model can be instantiated as follows\n", + "Please refer to the [ASE documentation](https://wiki.fysik.dtu.dk/ase/ase/calculators/calculators.html) to see how to use ASE calculators.\n", + "\n", + "An ASE calculator of a trained model can be instantiated as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from ase.io import read\n", + "from apax.md import ASECalculator\n", + "from ase.md.langevin import Langevin\n", + "from ase import units\n", + "import numpy as np\n", + "from ase.io.trajectory import Trajectory\n", + "\n", + "\n", + "# read starting structure and define modelpath\n", + "atoms = read(file_path, index=0)\n", + "model_dir = data_path / f\"models/{experiment}\"\n", + "\n", + "\n", + "# initiolize the apax ase calculator and assign it to the starting structure\n", + "calc = ASECalculator(model_dir=model_dir)\n", + "atoms.calc = calc\n", + "\n", "\n", - "CODE\n", + "# perform MD simulation\n", + "dyn = Langevin(\n", + " atoms=atoms,\n", + " timestep=0.5 * units.fs,\n", + " temperature_K=300,\n", + " friction=0.01 / units.fs,\n", + ")\n", "\n", - "Please refer to the ASE documentation LINK to see how to use ASE calculators." + "traj = Trajectory('example.traj', 'w', atoms)\n", + "dyn.attach(traj.write, interval=100)\n", + "dyn.run(1000)\n", + "traj.close()" ] }, { @@ -43,8 +154,8 @@ "## JaxMD\n", "\n", "While the ASE interface is convenient and flexible, it is not meant for high performance applications.\n", - "For these purposes, apax comes with an interface to JaxMD.\n", - "JaxMD LINK is a high performance molecular dynamics engine built on top of Jax LINK.\n", + "For these purposes, apax comes with an interface to [JaxMD](https://jax-md.readthedocs.io/en/main/#).\n", + "JaxMD is a high performance molecular dynamics engine built on top of [Jax](https://jax.readthedocs.io/en/latest/index.html).\n", "The CLI provides easy access to standard NVT and NPT simulations.\n", "More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). \n", "Trained apax models can of course be used as `energy_fn` in such custom simulations.\n", @@ -56,31 +167,128 @@ "metadata": {}, "source": [ "### Configuration\n", - "We can once again use the template command to give ourselves a quickstart.\n", - "\n", - "`apax template md --minimal`\n", + "We can once again use the template command to give ourselves a quickstart.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "!apax template md" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "Open the config and specify the starting structure and simulation parameters.\n", "If you specify the data set file itself, the first structure of the data set is going to be used as the initial structure.\n", "Your `md_config_minimal.yaml` should look similar to this:\n", "\n", "```yaml\n", + "ensemble:\n", + " temperature: 300 # K\n", + " \n", "duration: 20_000 # fs\n", - "initial_structure: md17.extxyz\n", - "```\n", + "initial_structure: project/benzene_mod.xyz\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "config_path = Path(\"md_config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"initial_structure\": str(file_path), # if the model from example 01 is used change this\n", + " \"duration\": 1000, #fs\n", + " \"ensemble\": {\n", + " \"temperature\": 300,\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"md_config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "As with training configurations, we can use the `validate` command to ensure our input is valid before we submit the calculation.\n" ] }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "md_config.yaml is a valid MD config.\n" + ] + } + ], + "source": [ + "!apax validate md md_config.yaml" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the simulation\n", "\n", - "The simulation can be started by running\n", + "The simulation can be started by running" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 12:39:38 | reading structure\n", + "INFO | 12:39:39 | Unable to initialize backend 'cuda': \n", + "INFO | 12:39:39 | Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n", + "INFO | 12:39:39 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", + "INFO | 12:39:39 | initializing model\n", + "INFO | 12:39:39 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/benzene_md/best\n", + "INFO | 12:39:39 | Initializing new trajectory file at md/md.h5\n", + "INFO | 12:39:39 | initializing simulation\n", + "INFO | 12:39:41 | running simulation for 1.0 ps\n", + "Simulation: 100%|███████████████████████████████████| 2000/2000 [00:10<00:00, 183.72it/s, T=196.3 K]\n", + "INFO | 12:39:52 | simulation finished after elapsed time: 10.93 s\n" + ] + } + ], + "source": [ + "!apax md config.yaml md_config.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "`apax md config.yaml md_config_minimal.yaml`\n", "\n", "where `config.yaml` is the configuration file that was used to train the model.\n", "\n", @@ -98,6 +306,29 @@ "TODO" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To remove all the created files and clean up yor working directory run" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!rm -r project md config.yaml example.traj md_config.yaml" + ] + }, { "cell_type": "code", "execution_count": null, @@ -107,8 +338,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "apax", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" } }, "nbformat": 4, From 234d854eb53fd1347f8018dc4b51c104f2f13cdb Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 18:23:41 +0100 Subject: [PATCH 094/192] linting --- apax/train/callbacks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 07ba69c0..e50b1053 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -27,8 +27,6 @@ def handle_value(k): if self.keys is None: self.keys = sorted(logs.keys()) - # When validation_freq > 1, `val_` keys are not in first epoch logs - # Add the `val_` keys so that its part of the fieldnames of writer. if not self.writer: From 107439ddbba6af7516832b0c94b9d3d0faf81789 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 6 Mar 2024 18:47:34 +0100 Subject: [PATCH 095/192] on_batch_begin hook to on_batch_end --- apax/train/callbacks.py | 2 +- apax/train/eval.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index e50b1053..09567346 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -13,7 +13,7 @@ class CSVLoggerApax(CSVLogger): def __init__(self, filename, separator=",", append=False): super().__init__(filename, separator=",", append=False) - def on_test_batch_begin(self, batch, logs=None): + def on_test_batch_end(self, batch, logs=None): logs = logs or {} def handle_value(k): diff --git a/apax/train/eval.py b/apax/train/eval.py index af57afb9..a72777da 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -91,7 +91,7 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal batch_end_time = time.time() batch_metrics.update({"time": batch_end_time - batch_start_time}) - callbacks.on_test_batch_begin(batch=batch_idx, logs=batch_metrics) + callbacks.on_test_batch_end(batch=batch_idx, logs=batch_metrics) batch_pbar.set_postfix(test_loss=batch_metrics["test_loss"]) batch_pbar.update() From 603282ba28afab6206aad9c5e73660b1a6f51788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 8 Mar 2024 18:28:04 +0100 Subject: [PATCH 096/192] removed unused jax nl in datapipeline --- apax/data/preprocessing.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index c3d65eaa..4b90b9e9 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -15,32 +15,6 @@ log = logging.getLogger(__name__) -def initialize_nbr_fn(atoms: Atoms, cutoff: float) -> Callable: - neighbor_fn = None - default_box = 100 - box = jnp.asarray(atoms.cell.array) - - if np.all(box < 1e-6): - displacement_fn, _ = space.free() - box = default_box - - neighbor_fn = partition.neighbor_list( - displacement_or_metric=displacement_fn, - box=box, - r_cutoff=cutoff, - format=partition.Sparse, - fractional_coordinates=False, - ) - - return neighbor_fn - - -@jax.jit -def extract_nl(neighbors, position): - neighbors = neighbors.update(position) - return neighbors - - def dataset_neighborlist( positions: list[np.array], box: list[np.array], From 35b83bea2a2398f2179afbdb4b37f2ac45ea5818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 8 Mar 2024 18:53:22 +0100 Subject: [PATCH 097/192] removed use of atoms list in dataset nl --- apax/data/preprocessing.py | 60 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 4b90b9e9..8d945e2d 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -15,11 +15,40 @@ log = logging.getLogger(__name__) +def compute_nl(position, box, r_max): + if np.all(box < 1e-6): + cell, cell_origin = get_shrink_wrapped_cell(position) + idxs_i, idxs_j = neighbour_list( + "ij", + positions=position, + cutoff=r_max, + cell=cell, + cell_origin=cell_origin, + pbc=[False, False, False], + ) + + neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) + + n_neighbors = neighbor_idxs.shape[1] + offsets = np.full([n_neighbors, 3], 0) + + else: + idxs_i, idxs_j, offsets = neighbour_list( + "ijS", + positions=position, + cutoff=r_max, + cell=cell, + ) + offsets = np.matmul(offsets, box) + neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) + return neighbor_idxs, offsets + + + def dataset_neighborlist( positions: list[np.array], - box: list[np.array], + boxs: list[np.array], r_max: float, - atoms_list, disable_pbar: bool = False, ) -> list[int]: """Calculates the neighbor list of all systems within positions using @@ -50,31 +79,8 @@ def dataset_neighborlist( disable=disable_pbar, leave=True, ) - for i, position in enumerate(positions): - if np.all(box[i] < 1e-6): - cell, cell_origin = get_shrink_wrapped_cell(position) - idxs_i, idxs_j = neighbour_list( - "ij", - positions=position, - cutoff=r_max, - cell=cell, - cell_origin=cell_origin, - pbc=[False, False, False], - ) - - neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) - - n_neighbors = neighbor_idxs.shape[1] - offsets = np.full([n_neighbors, 3], 0) - else: - idxs_i, idxs_j, offsets = neighbour_list( - "ijS", - atoms_list[i], - r_max, - ) - offsets = np.matmul(offsets, box[i]) - neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) - + for position, box in zip(positions, boxs): + neighbor_idxs, offsets = compute_nl(position, box, r_max) offset_list.append(offsets) idx_list.append(neighbor_idxs) nl_pbar.update() From e259b20b39b34721e19fb4247c97e243ab8df0e6 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Sun, 10 Mar 2024 16:10:03 +0100 Subject: [PATCH 098/192] eval fix --- apax/train/eval.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apax/train/eval.py b/apax/train/eval.py index a72777da..cefcb671 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -36,7 +36,13 @@ def load_test_data( ): # TODO double code run.py in progress log.info("Running Input Pipeline") os.makedirs(eval_path, exist_ok=True) - if config.data.data_path is not None: + + if config.data.test_data_path is not None: + log.info(f"Read test data file {config.data.test_data_path}") + atoms_list = load_data(config.data.test_data_path) + atoms_list = atoms_list[:n_test] + + elif config.data.data_path is not None: log.info(f"Read data file {config.data.data_path}") atoms_list = load_data(config.data.data_path) @@ -54,12 +60,6 @@ def load_test_data( atoms_list, _ = split_atoms(atoms_list, test_idxs) - elif config.data.test_data_path is not None: - log.info(f"Read test data file {config.data.test_data_path}") - atoms_list, label_dict = load_data(config.data.test_data_path) - atoms_list = atoms_list[:n_test] - for key, val in label_dict.items(): - label_dict[key] = val[:n_test] else: raise ValueError("input data path/paths not defined") @@ -80,6 +80,7 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal 0, test_ds.n_data, desc="Structure", ncols=100, disable=False, leave=True ) for batch_idx in range(test_ds.n_data): + callbacks.on_test_batch_begin(batch_idx) batch = next(batch_test_ds) batch_start_time = time.time() From 488f04933a6a0a20cc22a4a757e76bd1699e36e4 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Sun, 10 Mar 2024 16:10:24 +0100 Subject: [PATCH 099/192] new dataset and helper --- apax/utils/datasets.py | 16 ++++++++++++++++ apax/utils/helpers.py | 31 ++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 3819a12c..788df425 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -36,6 +36,22 @@ def download_benzene_DFT(data_path): return new_file_path +def download_etoh_ccsdt(data_path): + url = "http://www.quantum-machine.org/gdml/data/xyz/ethanol_ccsd_t.zip" + file_path = data_path / "ethanol_ccsd_t.zip" + + os.makedirs(data_path, exist_ok=True) + urllib.request.urlretrieve(url, file_path) + + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(data_path) + + test_file_path = data_path / "ethanol_ccsd_t-test.xyz" + train_file_path = data_path / "ethanol_ccsd_t-train.xyz" + os.remove(file_path) + + return train_file_path, test_file_path + def download_md22_benzene_CCSDT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene_ccsd_t.zip" file_path = data_path / "benzene_ccsdt.zip" diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 35c96d33..1b1dba70 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -1,5 +1,5 @@ import yaml - +import csv def setup_ase(): """Add uncertainty keys to ASE all properties. @@ -17,8 +17,33 @@ def mod_config(config_path, updated_config): config_dict = yaml.safe_load(stream) for key, new_value in updated_config.items(): - if isinstance(config_dict[key], dict): - config_dict[key].update(new_value) + if key in config_dict.keys(): + if isinstance(config_dict[key], dict): + config_dict[key].update(new_value) + else: + config_dict[key] = new_value else: config_dict[key] = new_value return config_dict + + +def load_csv_metrics(path): + data_dict = {} + + with open(path, 'r') as file: + reader = csv.reader(file) + + # Extract the headers (keys) from the first row + headers = next(reader) + + # Initialize empty lists for each key + for header in headers: + data_dict[header] = [] + + # Read the rest of the rows and append values to the corresponding key + for row in reader: + for idx, value in enumerate(row): + key = headers[idx] + data_dict[key].append(float(value)) + + return data_dict \ No newline at end of file From 0ab619c23e115cf81762a65fe77439c8c379b388 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Sun, 10 Mar 2024 16:10:40 +0100 Subject: [PATCH 100/192] example 01 update --- examples/01_Model_Training.ipynb | 672 ++++++++++++++----------------- 1 file changed, 299 insertions(+), 373 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index a73c3b2c..d640a0db 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -31,12 +31,13 @@ "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets, download_md22_benzene_CCSDT\n", + "from apax.utils.datasets import mod_md_datasets, download_etoh_ccsdt\n", "\n", "data_path = Path(\"project\")\n", "\n", - "file_path = download_benzene_DFT(data_path)\n", - "file_path = mod_md_datasets(file_path)" + "train_file_path, test_file_path = download_etoh_ccsdt(data_path)\n", + "train_file_path = mod_md_datasets(train_file_path)\n", + "test_file_path = mod_md_datasets(test_file_path)\n" ] }, { @@ -114,71 +115,25 @@ "metadata": {}, "source": [ "Open the resulting `config.yaml` file in an editor of your choice and make sure to fill in the data path field with the name of the data set you just downloaded.\n", - "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Further, the units of the labels have to be specified. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset\n", + "For the purposes of this tutorial we will train on 1000 data points and validate the model on 200 more during the training. Further, the units of the labels have to be specified. Random splitting is done by apax but it is also possible to input a pre-splitted training and validation dataset.\n", "\n", - "The filled in configuration file should look similar to this one.\n", - "\n", - "```yaml\n", - "epoch: 1000\n", - "data:\n", - " data_path: md17.extexyz\n", - " epochs: 1000\n", - " n_train: 1000\n", - " energy_unit: kcal/mol\n", - " pos_unit: Ang\n", - " ....\n", - "```\n", - "\n", - "It also can be modefied with the utils function `mod_config` provided by Apax.\n" + "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [], - "source": [ - "from apax.utils.helpers import mod_config\n", - "import yaml\n", - "\n", - "\n", - "config_path = Path(\"config.yaml\")\n", - "\n", - "config_updates = {\n", - " \"n_epochs\": 10,\n", - " \"data\": {\n", - " \"experiment\": \"benzene_dft_cli\",\n", - " \"directory\": \"project/models\",\n", - " \"data_path\": str(file_path),\n", - " \"energy_unit\": \"kcal/mol\",\n", - " \"pos_unit\": \"Ang\",\n", - " }\n", - "}\n", - "config_dict = mod_config(config_path, config_updates)\n", - "\n", - "with open(\"config.yaml\", \"w\") as conf:\n", - " yaml.dump(config_dict, conf, default_flow_style=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "In order to check whether the a configuration file is valid, we provide the `validate` command. This is especially convenient when submitting training runs on a compute cluster.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[32mSuccess!\u001b[0m\n", - "config.yaml is a valid training config.\n" + "1 validation error for Config\n", + "n_epochs\n", + " Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='', input_type=str]\n", + " For further information visit https://errors.pydantic.dev/2.6/v/int_parsing\n", + "\u001b[31mConfiguration Invalid!\u001b[0m\n" ] } ], @@ -190,44 +145,91 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file.\n", - "For example, changing `epochs` to `-1000`, validate will give the following feedback to the user:" + "Configuration files are validated using Pydantic and the errors provided by the `validate` command give precise instructions on how to fix the input file. The filled in configuration file should look similar to this one.\n", + "\n", + "```yaml\n", + "data:\n", + " batch_size: 32\n", + " data_path: project/ethanol_ccsd_t-train_mod.xyz\n", + " directory: project/models\n", + " energy_unit: kcal/mol\n", + " experiment: benzene_dft_cli\n", + " n_train: 990\n", + " n_valid: 10\n", + " pos_unit: Ang\n", + " valid_batch_size: 100\n", + "loss:\n", + "- name: energy\n", + "- name: forces\n", + " weight: 4.0\n", + "metrics:\n", + "- name: energy\n", + " reductions:\n", + " - mae\n", + "- name: forces\n", + " reductions:\n", + " - mae\n", + " - mse\n", + "model:\n", + " descriptor_dtype: fp64\n", + "n_epochs: 100\n", + "\n", + "```\n", + "\n", + "It also can be modefied with the utils function `mod_config` provided by Apax." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ + "from apax.utils.helpers import mod_config\n", + "import yaml\n", + "\n", + "\n", + "config_path = Path(\"config.yaml\")\n", + "\n", "config_updates = {\n", - " \"n_epochs\": -1000,\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"n_train\": 990,\n", + " \"n_valid\": 10,\n", + " \"valid_batch_size\": 1,\n", + " \"experiment\": \"benzene_dft_cli\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(train_file_path),\n", + " \"test_data_path\": str(test_file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " },\n", + " \"model\": {\n", + " \"descriptor_dtype\": \"fp64\"\n", + " },\n", "}\n", "config_dict = mod_config(config_path, config_updates)\n", "\n", - "with open(\"error_config.yaml\", \"w\") as conf:\n", + "with open(\"config.yaml\", \"w\") as conf:\n", " yaml.dump(config_dict, conf, default_flow_style=False)" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "1 validation error for Config\n", - "n_epochs\n", - " Input should be greater than 0 [type=greater_than, input_value=-1000, input_type=int]\n", - " For further information visit https://errors.pydantic.dev/2.6/v/greater_than\n", - "\u001b[31mConfiguration Invalid!\u001b[0m\n" + "\u001b[32mSuccess!\u001b[0m\n", + "config.yaml is a valid training config.\n" ] } ], "source": [ - "!apax validate train error_config.yaml" + "!apax validate train config.yaml" ] }, { @@ -241,29 +243,29 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "INFO | 17:12:25 | Initializing Callbacks\n", - "INFO | 17:12:25 | Initializing Loss Function\n", - "INFO | 17:12:25 | Initializing Metrics\n", - "INFO | 17:12:25 | Running Input Pipeline\n", - "INFO | 17:12:25 | Read data file project/benzene_mod.xyz\n", - "INFO | 17:12:25 | Loading data from project/benzene_mod.xyz\n", - "INFO | 17:12:36 | Precomputing neighborlists\n", - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12876.51it/s]\n", - "INFO | 17:12:36 | Computing per element energy regression.\n", - "INFO | 17:12:42 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 12902.77it/s]\n", - "INFO | 17:12:43 | Initializing Model\n", - "INFO | 17:12:43 | initializing 1 models\n", - "INFO | 17:12:49 | Initializing Optimizer\n", - "INFO | 17:12:49 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████████| 10/10 [00:27<00:00, 2.77s/it, val_loss=0.63]\n" + "INFO | 15:03:19 | Initializing Callbacks\n", + "INFO | 15:03:19 | Initializing Loss Function\n", + "INFO | 15:03:19 | Initializing Metrics\n", + "INFO | 15:03:19 | Running Input Pipeline\n", + "INFO | 15:03:19 | Read data file project/ethanol_ccsd_t-train_mod.xyz\n", + "INFO | 15:03:19 | Loading data from project/ethanol_ccsd_t-train_mod.xyz\n", + "INFO | 15:03:19 | Precomputing neighborlists\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 990/990 [00:00<00:00, 14011.30it/s]\n", + "INFO | 15:03:20 | Computing per element energy regression.\n", + "INFO | 15:03:26 | Precomputing neighborlists\n", + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 8937.36it/s]\n", + "INFO | 15:03:26 | Initializing Model\n", + "INFO | 15:03:26 | initializing 1 models\n", + "INFO | 15:03:32 | Initializing Optimizer\n", + "INFO | 15:03:32 | Beginning Training\n", + "Epochs: 100%|████████████████████████████████████| 100/100 [02:31<00:00, 1.52s/it, val_loss=0.0694]\n" ] } ], @@ -294,16 +296,16 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 11830.34it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11579.76it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:38<00:00, 2.19s/it, val_loss=0.31]\n" + "Precomputing NL: 100%|██████████████████████████████████████████| 990/990 [00:00<00:00, 8954.80it/s]\n", + "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 4902.18it/s]\n", + "Epochs: 100%|████████████████████████████████████| 100/100 [02:32<00:00, 1.52s/it, val_loss=0.0694]\n" ] } ], @@ -315,14 +317,9 @@ "config_path = Path(\"config.yaml\")\n", "\n", "config_updates = {\n", - " \"n_epochs\": 100,\n", " \"data\": {\n", " \"experiment\": \"benzene_dft_script\",\n", - " \"directory\": \"project/models\",\n", - " \"data_path\": str(file_path),\n", - " \"energy_unit\": \"kcal/mol\",\n", - " \"pos_unit\": \"Ang\",\n", - " }\n", + " },\n", "}\n", "\n", "config_dict = mod_config(config_path, config_updates)\n", @@ -332,12 +329,12 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { - "image/png": "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99yWLLZq1YpnnnmGiIgIRowYwebNm9116mt3hcLc+yVZFELcyKQotxC657ZkcebMmZw5c4Z58+aRlJTELbfcQuPGjXn77bcvW5Wg0immMLeqqhdbFqXothDiEjVr1rysYPd1SUrnCKF7bh2zaDKZuO+++1i6dCmnTp1i4MCBvPDCC0RHR3PPPffw+++/uzOcknMmi67d0GfTcknNtmE0KNQN8/dAYEIId4uPj+fUqVPO51u3bmXs2LF88sknLvvt3bu39OswV0ZSOkcI3fPIBJetW7cydepU3nnnHcLCwpg0aRKhoaHceeedPPPMM54I6coKk8W/TXAp7IKuW80fby8plSOEHgwcOJDVq1cDkJCQQK9evdi6dSvPP/88L7/8soejqwBSOkcI3XNbspiUlMQ777xD06ZN6dq1K+fOneOrr77ixIkTvPTSS3z66aesWLGC2bNnuyukkru0MPclCmdCSxe0EPqxd+9e2rdvD8DXX39N06ZN2bhxI19++WWRhbSve8aCbmhpWRRCt9xWZ7FGjRrUqVOHYcOGMXToUKpVq3bZPs2bN6ddu3buCqnknLOhXVsWC8crNooMcHdEQggPsdlsWCxab8Nvv/1G//79AWjYsCFnz571ZGgVwyClc4TQO7cli6tWraJr165X3CcwMNDZvVOpFNOy+Fdhy2KkLO0nhF40adKE2bNnc8cdd7By5UpeeeUVAM6cOUPVqlU9HF0FMEjLohB657Zu6KslipVa4aotl4xZjE/JJi4lG6NBkXWghdCRN954g48//pju3bszYMAAWrRoAcAPP/zg7J6+oRhlzKIQeue2lsVWrVoVucKJoih4e3tTt25dhg4dSo8ePdwVUskV0bK47vA5AFpFBxPkcwOUxxBClEj37t1JTk4mPT2dKlWqOLc//vjj+Pr6ejCyCuJsWZRuaCH0ym0ti3369OHYsWP4+fnRo0cPevTogb+/P0ePHqVdu3acPXuWnj17snTpUneFVHLOMYsX6yyuPagli93qXz72UghxY1NVldjYWD7++GMyMjIAMJvNN2ayKEW5hdA9t7UsJicn869//YsXXnjBZfurr77KyZMnWbFiBVOnTuWVV17h7rvvdldYJeNsWdSSRZvdwcaj5wHo1kCSRSH05OTJk/Tp04e4uDjy8vLo1asXAQEBvPHGG+Tl5VXOig7XQkrnCKF7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LUIPM5sMmAwKVrXw27W0LAohXB0/fpzGjRsD8N1333HnnXcybdo0Zs2axS+//FLi42RlZdGiRQtmzZpV5Otvvvkm77//PrNnz2bLli34+fnRu3dvcnMr8EusFOUWQvfKlCwOHDiQ1atXA5CQkECvXr3YunUrzz//PC+//HK5BlgZ+HgZL2lZlDGLQghXZrOZ7OxsAH777Tduv/12AEJCQpwtjiXRt29fXn31Ve69997LXlNVlZkzZzJ58mTuvvtumjdvzvz58zlz5sxlLZDlyrncn7QsCqFXZUoW9+7dS/v27QH4+uuvadq0KRs3buTLL7/k888/L8/4KgWfS9eHlgkuQoi/6dKlC+PHj+eVV15h69atzmX/Dh06RI0aNcrlHMePHychIYGePXs6twUFBdGhQwc2bdpU5Hvy8vJIT093eZSalM4RQvfKlCzabDYsFgugfYvu378/AA0bNuTs2bPlF10l4WM2koeUzhFCFO2DDz7AZDLx7bff8tFHH1G9enUAfvnlF/r06VMu50hISAAgPDzcZXt4eLjztb+bPn06QUFBzkeZhgVJ6RwhdK9MpXOaNGnC7NmzueOOO1i5ciWvvPIKAGfOnHHWF7uRuHZDywQXIYSrmJgYfvrpp8u2v/vuux6I5qJJkya5TLBJT08vfcIopXOE0L0yJYtvvPEG9957L2+99RZDhgyhRYsWAPzwww/O7ukbiY/ZSIbqoz3Jy/BsMEKISslut7NkyRL2798PaF+q+/fvj9FoLJfjR0REAJCYmEhkZKRze2JiIi1btizyPRaLxdkLVGay3J8Qulembuju3buTnJxMcnIyc+fOdW5//PHHmT17dqmPN2vWLGrVqoW3tzcdOnRg69atJXrfwoULURSFe+65p9TnLA1fs5E0/LQnuakVei4hxPXnyJEjNGrUiMGDB7N48WIWL17MI488QpMmTTh69Gi5nKN27dpERESwatUq57b09HS2bNlCx44dy+UcRTJK6Rwh9K7MdRZVVSU2NpaPP/6YjAyttc1sNuPr61uq4yxatIjx48czdepUduzYQYsWLejduzdJSUlXfN+JEyd45pln6Nq1a1kvocR8vIykqwXJYs51XmBXCFHunn76aerUqUN8fDw7duxgx44dxMXFUbt2bZ5++ukSHyczM5Ndu3axa9cuQJvUsmvXLuLi4lAUhbFjx/Lq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5s+fz6233spbb73Fj370IzweD3PmzEnGd6z9J92xA9x88800NjYyYsQILMsikUhw9913M3v2bIBeH3+77sRZXV1NYWFhynqXy0Vubm6v6ktvovmvZ2j+Sw/Nfyef/7RYPI3MnTuXTZs28cYbb6Q7lG7Zs2cP8+bNY+nSpfh8vnSHc1Js26aiooJf/epXAIwbN45NmzbxyCOPMGfOnDRHd2J/+9vfeOKJJ3jyySc555xz2LhxI9dffz0lJSV9In6ljqT5r+do/jvz6MfQXcjPz8eyrKO+eVZTU0NxcXGaouraddddx4svvsjrr7/OwIEDk8uLi4uJRqPU19entO8N/Vi/fj21tbWcf/75uFwuXC4XK1as4IEHHsDlclFUVNRrY+/fvz+jRo1KWTZy5Eh2794NkIyvt+4/N954IzfffDPf/OY3GT16NN/5zne44YYbWLBgAdD742/XnTiLi4upra1NWR+Px6mrq+tVfelNNP+depr/0kfz38nnPy0Wu+DxeLjgggtYtmxZcplt2yxbtoxJkyalMbJUIsJ1113Hs88+y2uvvcbgwYNT1l9wwQW43e6UflRVVbF79+609+Piiy/mvffeY+PGjclbRUUFs2fPTv7eW2OfMmXKUVN0bN26lUGDBgEwePBgiouLU2JvbGxkzZo1aY8doLW1FdNMfflbloVt20Dvj79dd+KcNGkS9fX1rF+/Ptnmtddew7ZtKisrezzmvkDz36mn+S99NP99gvz3ab+dczpbtGiReL1e+eMf/ygffPCBfP/735dgMCjV1dXpDi3p2muvlZycHFm+fLns378/eWttbU22ueaaa6SsrExee+01WbdunUyaNEkmTZqUxqi71vnbgCK9N/a1a9eKy+WSu+++W7Zt2yZPPPGEBAIB+ctf/pJsc88990gwGJTnn39e3n33XfnKV77Sa6aOmDNnjgwYMCA5dcQzzzwj+fn58tOf/jTZprfE39TUJBs2bJANGzYIIL/5zW9kw4YN8tFHH3U7zksvvVTGjRsna9askTfeeEOGDRumU+ecgOa/nqf5r2do/jv5/KfF4gk8+OCDUlZWJh6PRyZMmCCrV69Od0gpgGPeFi5cmGwTCoXkBz/4gfTr108CgYB89atflf3796cv6OM4Mln25thfeOEFOffcc8Xr9cqIESPk0UcfTVlv27bcfvvtUlRUJF6vVy6++GKpqqpKU7SpGhsbZd68eVJWViY+n0+GDBkit912m0QikWSb3hL/66+/fsx9fM6cOd2O89ChQzJr1izJzMyU7OxsufLKK6WpqanH+9LXaP7rWZr/eobmv5PPf4ZIpynLlVJKKaWU6kTPWVRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSXtFhUSimllFJd0mJRKaWUUkp1SYtFpZRSSinVJS0WlVJKKaVUl7RYVKobli9fjmEY1NfXpzsUpZTqUZr/lBaLSimllFKqS1osKqWUUkqpLmmxqPoE27ZZsGABgwcPxu/3M3bsWJ5++mmg4yOSJUuWMGbMGHw+HxMnTmTTpk0p9/H3v/+dc845B6/XS3l5Offdd1/K+kgkwk033URpaSler5ehQ4fyhz/8IaXN+vXrqaioIBAIMHnyZKqqqk5tx5VSZzzNfyrtRKk+4Je//KWMGDFCXn75Zdm+fbssXLhQvF6vLF++XF5//XUBZOTIkfLKK6/Iu+++K1/84helvLxcotGoiIisW7dOTNOUO++8U6qqqmThwoXi9/tl4cKFyce4/PLLpbS0VJ555hnZvn27vPrqq7Jo0SIRkeRjVFZWyvLly+X999+Xz33uczJ58uR0PB1KqTOI5j+Vblosql4vHA5LIBCQN998M2X51VdfLbNmzUomsvbEJiJy6NAh8fv98tRTT4mIyLe+9S255JJLUra/8cYbZdSoUSIiUlVVJYAsXbr0mDG0P8arr76aXLZkyRIBJBQKfSb9VEqpI2n+U72Bfgyter0PP/yQ1tZWLrnkEjIzM5O3P//5z2zfvj3ZbtKkScnfc3NzOfvss9m8eTMAmzdvZsqUKSn3O2XKFLZt20YikWDjxo1YlsXUqVOPG8uYMWOSv/fv3x+A2traT91HpZQ6Fs1/qjdwpTsApU6kubkZgCVLljBgwICUdV6vNyVhflJ+v79b7dxud/J3wzAA53wipZQ6FTT/qd5ARxZVrzdq1Ci8Xi+7d+9m6NChKbfS0tJku9WrVyd/P3z4MFu3bmXkyJEAjBw5kpUrV6bc78qVKxk+fDiWZTF69Ghs22bFihU90ymllOoGzX+qN9CRRdXrZWVl8ZOf/IQbbrgB27a58MILaWhoYOXKlWRnZzNo0CAA7rzzTvLy8igqKuK2224jPz+fGTNmAPDjH/+Y8ePHc9dddzFz5kxWrVrFQw89xO9+9zsAysvLmTNnDldddRUPPPAAY8eO5aOPPqK2tpbLL788XV1XSp3hNP+pXiHdJ00q1R22bcv9998vZ599trjdbikoKJDp06fLihUrkidfv/DCC3LOOeeIx+ORCRMmyDvvvJNyH08//bSMGjVK3G63lJWVyb333puyPhQKyQ033CD9+/cXj8cjQ4cOlccff1xEOk7wPnz4cLL9hg0bBJCdO3ee6u4rpc5gmv9UuhkiIuksVpX6tJYvX85FF13E4cOHCQaD6Q5HKaV6jOY/1RP0nEWllFJKKdUlLRaVUkoppVSX9GNopZRSSinVJR1ZVEoppZRSXdJiUSmllFJKdUmLRaWUUkop1SUtFpVSSimlVJe0WFRKKaWUUl3SYlEppZRSSnVJi0WllFJKKdUlLRaVUkoppVSX/j9nEtQsXpP9AgAAAABJRU5ErkJggg==", + "image/png": "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5f7772fo0KEujKxiOI5ZTAdVtW2BKoRwG061LP7www/07du30PFHHnmEH374AYC+ffty8ODBa4uuCvDJb1nMs7csSje0EO5s7dq1jB8/HoPB4HA8MjKS06dPuyiqiuOwzqJqBVOmawMSQlQ6p5JFDw8PNmzYUOj4hg0b8PDwAMBqtdp/vp4VdEObKNjuL8eF0QghXM1qtWKxWAodP3XqFL6+vi6IqGIFeOnJxoi54J8LmeQihNtxqhv6mWeeYdiwYWzfvt2+luLWrVv54osveOmllwD4888/adWqVbkF6ioFLYvZSv43a1OGC6MRQrjanXfeydSpU+17QSuKQkZGBhMnTqR3794ujq78BXgaAIUM1ZMAJTN/+ZxwV4clhKhETiWL48ePJyoqio8//phvvvkGgIYNGzJjxgz69esHwLBhw3jqqafKL1IXKUgWsxQf24EcGeAthDt7//336dGjB02aNCEnJ4d+/fpx+PBhgoOD+f77710dXrnz97L1qqSrXrZkUWZEC+F2ytwNbTabee211+jSpQsbN24kOTmZ5ORkNm7caE8UATw9PUvshl6zZg333HMPNWrUQFEUFixYUOLzV61axc0334zRaKR+/foVvhert1ELQLribTuQnVKhzxNCVG21atVi9+7dvPzyy4wePZro6Gjeeustdu7cSUhIiKvDK3e+Rh2KAhmyP7QQbqvMLYs6nY533nmHAQMGXPPDMzMzadmyJYMHD+aBBx4osfzx48e56667GDZsGN999x3Lly/niSeeIDw8nB49elxzPEUpGLOYRn6yKC2LQrg9nU5H//796d+/v6tDqXAajYK/p540s+ziIoS7cqob+vbbb2f16tVERkZe08N79epFr169Sl1++vTpREVF8f777wPQuHFj1q1bx5QpU4pNFnNzc8nNvbzcTVpa2So63/xkMVXN/1YtyaIQbi0uLo7Q0FAGDx7scHzmzJmcP3+eF1980UWRVZwATz3paQV1oCSLQrgbp5LFXr16MXbsWPbs2UPr1q3x9vZ2ON+nT59yCe7fNm7cSPfu3R2O9ejRg1GjRhV7TVxcHJMmTXL6mQUti8nWgpbFFKfvJYS4/n322WfMmTOn0PGmTZvyyCOP3JDJor+XgYw02fJPCHflVLL49NNPA/DBBx8UOqcoSpHLSpSHxMREQkNDHY6FhoaSlpZGdnY2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", "text/plain": [ "
" ] @@ -350,28 +347,12 @@ "import csv\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "from apax.utils.helpers import load_csv_metrics\n", "\n", - "\n", - "path = \"project/models/benzene_dft_script/log.csv\"\n", - "\n", + "metrics_path = \"project/models/benzene_dft_script/log.csv\"\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", - "data_dict = {}\n", "\n", - "with open(path, 'r') as file:\n", - " reader = csv.reader(file)\n", - "\n", - " # Extract the headers (keys) from the first row\n", - " headers = next(reader)\n", - "\n", - " # Initialize empty lists for each key\n", - " for header in headers:\n", - " data_dict[header] = []\n", - "\n", - " # Read the rest of the rows and append values to the corresponding key\n", - " for row in reader:\n", - " for idx, value in enumerate(row):\n", - " key = headers[idx]\n", - " data_dict[key].append(float(value))\n", + "data_dict = load_csv_metrics(metrics_path)\n", "\n", "fig, axes = plt.subplots(2, 2, constrained_layout=True)\n", "axes = axes.ravel()\n", @@ -403,50 +384,50 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 11736.50it/s]\n", - "Structure: 100%|█████████████████████████████| 5000/5000 [00:21<00:00, 232.32it/s, test_loss=0.0211]\n" + "Precomputing NL: 100%|█████████████████████████████████████████| 999/999 [00:00<00:00, 14303.45it/s]\n", + "Structure: 100%|███████████████████████████████| 999/999 [00:04<00:00, 220.62it/s, test_loss=0.0866]\n" ] } ], "source": [ "from apax.train.eval import eval_model\n", "\n", - "eval_model(config_dict, n_test=5000)" + "eval_model(config_dict)" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 5000/5000 [00:00<00:00, 12105.28it/s]\n", - "Structure: 100%|██████████████████████████████| 5000/5000 [00:17<00:00, 288.77it/s, test_loss=0.181]\n" + "Precomputing NL: 100%|█████████████████████████████████████████| 999/999 [00:00<00:00, 14147.08it/s]\n", + "Structure: 100%|███████████████████████████████| 999/999 [00:04<00:00, 239.88it/s, test_loss=0.0866]\n" ] } ], "source": [ - "!apax eval config.yaml --n-data 5000" + "!apax eval config.yaml" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -456,76 +437,10 @@ } ], "source": [ - "path = \"project/models/benzene_dft_script/eval/log.csv\"\n", - "\n", + "metrics_path = \"project/models/benzene_dft_script/eval/log.csv\"\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", - "data_dict = {}\n", - "\n", - "with open(path, 'r') as file:\n", - " reader = csv.reader(file)\n", - "\n", - " # Extract the headers (keys) from the first row\n", - " headers = next(reader)\n", "\n", - " # Initialize empty lists for each key\n", - " for header in headers:\n", - " data_dict[header] = []\n", - "\n", - " # Read the rest of the rows and append values to the corresponding key\n", - " for row in reader:\n", - " for idx, value in enumerate(row):\n", - " key = headers[idx]\n", - " data_dict[key].append(float(value))\n", - "\n", - "fig, axes = plt.subplots(1, 4, constrained_layout=True)\n", - "axes = axes.ravel()\n", - "fig.suptitle(f'Metrics', fontsize=16)\n", - "\n", - "for id, key in enumerate(keys):\n", - " test = np.array(data_dict[f\"test_{key}\"])\n", - "\n", - " axes[id].set_title(f'{key}')\n", - " axes[id].boxplot(test)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "path = \"project/models/benzene_dft_script/eval/log.csv\"\n", - "\n", - "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", - "data_dict = {}\n", - "\n", - "with open(path, 'r') as file:\n", - " reader = csv.reader(file)\n", - "\n", - " # Extract the headers (keys) from the first row\n", - " headers = next(reader)\n", - "\n", - " # Initialize empty lists for each key\n", - " for header in headers:\n", - " data_dict[header] = []\n", - "\n", - " # Read the rest of the rows and append values to the corresponding key\n", - " for row in reader:\n", - " for idx, value in enumerate(row):\n", - " key = headers[idx]\n", - " data_dict[key].append(float(value))\n", + "data_dict = load_csv_metrics(metrics_path)\n", "\n", "fig, axes = plt.subplots(1, 4, constrained_layout=True)\n", "axes = axes.ravel()\n", @@ -556,84 +471,15 @@ "## A Closer Look At Training Parameters" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Parameter | Default Value | Description |\n", - "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", - "| **n_epochs** | `` | Number of training epochs. |\n", - "| **seed** | 1 | Seed for initializing random numbers. |\n", - "| **patience** | None | Number of epochs without improvement before training termination. |\n", - "| **n_models** | 1 | Number of models trained simultaneously. |\n", - "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", - "| **Data** | | |\n", - "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", - "| experiment | apax | Model name distinguishing from others in directory. |\n", - "| data_path | `` | Path to single dataset file. |\n", - "| train_data_path | `` | Path to training dataset. |\n", - "| val_data_path | `` | Path to validation dataset. |\n", - "| test_data_path | `` | Path to test dataset. |\n", - "| n_train | 1000 | Number of training data points. |\n", - "| n_valid | 100 | Number of validation data points. |\n", - "| batch_size | 32 | Number of training examples evaluated at once. |\n", - "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", - "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", - "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", - "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", - "| pos_unit | Ang | Positional unit. |\n", - "| energy_unit | eV | Energy unit. |\n", - "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", - "| **Model** | | |\n", - "| n_basis | 7 | Number of Gaussian basis functions. |\n", - "| n_radial | 5 | Number of contracted basis functions. |\n", - "| nn | [512, 512] | Hidden layers and units. |\n", - "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", - "| r_min | 0.5 | Descriptor cutoff radius. |\n", - "| use_zbl | false | Use Zero-Body-Loss. |\n", - "| b_init | normal | Initialization scheme for biases. |\n", - "| descriptor_dtype | fp64 | Descriptor data type. |\n", - "| readout_dtype | fp32 | Readout data type. |\n", - "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", - "| **Loss** | | |\n", - "| loss_type | structures | Weighting scheme for atomic contributions. |\n", - "| name | energy | Quantity keyword. |\n", - "| weight | 1.0 | Weighting factor in loss function. |\n", - "| name | forces | Quantity keyword. |\n", - "| weight | 4.0 | Weighting factor in loss function. |\n", - "| **Metrics** | | |\n", - "| name | energy | Quantity keyword. |\n", - "| reductions | | List of reductions on target-prediction differences. |\n", - "| name | forces | Quantity keyword. |\n", - "| reductions | mae, mse | Reductions on target-prediction differences. |\n", - "| **Optimizer** | | |\n", - "| opt_name | adam | Optimizer name. |\n", - "| opt_kwargs | {} | Optimizer keyword arguments. |\n", - "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", - "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", - "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", - "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", - "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", - "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", - "| **Callbacks** | | |\n", - "| name | csv | Callback name. |\n", - "| **Progress Bar** | | |\n", - "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", - "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", - "| **Checkpoints** | | |\n", - "| ckpt_interval | 1 | Epochs between checkpoints. |\n", - "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", - "| reset_layers | [] | List of layers to reinitialize parameters. |\n" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", "\n", - "- **n_epochs**: ``\n", - " - Number of training epochs.\n" + "- **n_epochs**: int (required)\n", + "\n", + " >Number of training epochs.\n" ] }, { @@ -641,8 +487,9 @@ "metadata": {}, "source": [ "\n", - "- **seed**: 1\n", - " - Seed for initializing random numbers.\n" + "- **seed**: int (default = 1)\n", + " \n", + " >Seed for initializing random numbers.\n" ] }, { @@ -650,8 +497,9 @@ "metadata": {}, "source": [ "\n", - "- **patience**: None\n", - " - Number of epochs without improvement before training termination.\n" + "- **patience**: int (optional)\n", + "\n", + " >Number of epochs without improvement before training termination.\n" ] }, { @@ -659,8 +507,9 @@ "metadata": {}, "source": [ "\n", - "- **n_models**: 1\n", - " - Number of models trained simultaneously.\n" + "- **n_models**: int (default = 1)\n", + "\n", + " >Number of models trained simultaneously.\n" ] }, { @@ -668,8 +517,9 @@ "metadata": {}, "source": [ "\n", - "- **n_jitted_steps**: 1\n", - " - Number of train batches in a compiled loop. Can speed up for small batches." + "- **n_jitted_steps**: int (default = 1)\n", + "\n", + " >Number of train batches in a compiled loop. Can speed up for small batches." ] }, { @@ -677,53 +527,59 @@ "metadata": {}, "source": [ "- **Data**\n", - " - directory: models/\n", - " - Path to directory where training results and checkpoints are written.\n", + " - directory: str (default = \"/models\")\n", "\n", - " - experiment: apax\n", - " - Model name distinguishing from others in directory.\n", + " >Path to directory where training results and checkpoints are written.\n", "\n", - " - data_path: ``\n", - " - Path to single dataset file.\n", "\n", - " - train_data_path: ``\n", - " - Path to training dataset.\n", + " - experiment: str (default = \"apax\")\n", "\n", - " - val_data_path: ``\n", - " - Path to validation dataset.\n", + " >Model name distinguishing from others in directory. \n", "\n", - " - test_data_path: ``\n", - " - Path to test dataset.\n", "\n", - " - n_train: 1000\n", - " - Number of training data points.\n", + " - data_path: str (required if train_ and val_data_path is not specified)\n", + "\n", + " >Path to single dataset file.\n", + " \n", + "\n", + " - train_data_path: str (required if data_path is not specified)\n", + " >Path to training dataset.\n", + "\n", + " - val_data_path: str (required if data_path is not specified)\n", + " >Path to validation dataset.\n", + "\n", + " - test_data_path: str (optional)\n", + " >Path to test dataset.\n", + "\n", + " - n_train: int (default = 1000)\n", + " >Number of training data points.\n", " \n", - " - n_valid: 100\n", - " - Number of validation data points.\n", + " - n_valid: int (default = 100)\n", + " >Number of validation data points.\n", " \n", - " - batch_size: 32\n", - " - Number of training examples evaluated at once.\n", + " - batch_size: int (default = 32)\n", + " >Number of training examples evaluated at once.\n", " \n", - " - valid_batch_size: 100\n", - " - Number of validation examples evaluated at once.\n", + " - valid_batch_size: int (default = 100)\n", + " >Number of validation examples evaluated at once.\n", " \n", - " - shift_method: \"per_element_regression_shift\"\n", - " - Method for shifting.\n", + " - shift_method: str (default = \"per_element_regression_shift\")\n", + " >Method for shifting.\n", " \n", - " - shift_options: energy_regularization: 1.0\n", - " - Regularization magnitude for energy regression.\n", + " - shift_options: dict (default = {\"energy_regularization\": 1.0})\n", + " >Regularization magnitude for energy regression. #TODO fill in the other options\n", " \n", - " - shuffle_buffer_size: 1000\n", - " - Size of `tf.data` shuffle buffer.\n", + " - shuffle_buffer_size: int (default = 1000)\n", + " >Size of `tf.data` shuffle buffer.\n", " \n", - " - pos_unit: Ang\n", - " - Positional unit.\n", + " - pos_unit: str (default = \"Ang\")\n", + " >Positional unit.\n", " \n", - " - energy_unit: eV\n", - " - Energy unit.\n", + " - energy_unit: str (default = \"eV\")\n", + " >Energy unit.\n", " \n", - " - additional_properties_info:\n", - " - Dictionary of property name, shape pairs.\n", + " - additional_properties_info: dict (optional)\n", + " >Dictionary of property name, shape pairs.\n", " \n" ] }, @@ -732,35 +588,35 @@ "metadata": {}, "source": [ "- **Model**\n", - " - n_basis: 7\n", - " - Number of Gaussian basis functions.\n", + " - n_basis: int (default = 7)\n", + " >Number of Gaussian basis functions.\n", "\n", - " - n_radial: 5\n", - " - Number of contracted basis functions.\n", + " - n_radial: int (default = 5)\n", + " >Number of contracted basis functions.\n", "\n", - " - nn: [512, 512]\n", - " - Hidden layers and units.\n", + " - nn: list of int (default = [512, 512])\n", + " >Hidden layers and units.\n", "\n", - " - r_max: 6.0\n", - " - Maximum position of first basis function's mean.\n", + " - r_max: float (default = 6.0)\n", + " >Maximum position of first basis function's mean in angstrom.\n", "\n", - " - r_min: 0.5\n", - " - Descriptor cutoff radius.\n", + " - r_min: float (default = 0.5)\n", + " >Descriptor cutoff radius in angstrom.\n", "\n", - " - use_zbl: false\n", - " - Use emperical Ziegler-Biersack-Littmark potential.\n", + " - use_zbl: bool (default = false)\n", + " >Use emperical Ziegler-Biersack-Littmark potential.\n", "\n", - " - b_init: normal\n", - " - Initialization scheme for biases.\n", + " - b_init: str (default = \"normal\")\n", + " >Initialization scheme for biases. #TODO fill in the other options\n", "\n", - " - descriptor_dtype: fp64\n", - " - Descriptor data type.\n", + " - descriptor_dtype: str (default = \"fp64\")\n", + " >Descriptor data type.\n", "\n", - " - readout_dtype: fp32\n", - " - Readout data type.\n", + " - readout_dtype: str (default = \"fp32\")\n", + " >Readout data type.\n", "\n", - " - scale_shift_dtype: fp32\n", - " - Scale/Shift data type.\n", + " - scale_shift_dtype: str (default = \"fp32\")\n", + " >Scale/Shift data type.\n", " \n" ] }, @@ -769,20 +625,20 @@ "metadata": {}, "source": [ "- **Loss**\n", - " - loss_type: structures\n", - " - Weighting scheme for atomic contributions.\n", + " - loss_type: str (default = \"structures\")\n", + " >Weighting scheme for atomic contributions. #TODO fill in the other options\n", "\n", - " - name: energy\n", - " - Quantity keyword.\n", + " - name: str (default = \"energy\")\n", + " >Quantity keyword.\n", "\n", - " - weight: 1.0\n", - " - Weighting factor in loss function.\n", + " - weight: float (default = 1.0)\n", + " >Weighting factor in loss function.\n", "\n", - " - name: forces\n", - " - Quantity keyword.\n", + " - name: str (default = \"forces\")\n", + " >Quantity keyword.\n", "\n", - " - weight: 4.0\n", - " - Weighting factor in loss function." + " - weight: float (default = 4.0)\n", + " >Weighting factor in loss function." ] }, { @@ -791,17 +647,17 @@ "source": [ "\n", "- **Metrics**\n", - " - name: energy\n", - " - Quantity keyword.\n", + " - name: str (default = \"energy\")\n", + " >Quantity keyword.\n", " \n", " - reductions:\n", - " - List of reductions on target-prediction differences.\n", + " >List of reductions on target-prediction differences.\n", " \n", - " - name: forces\n", - " - Quantity keyword.\n", + " - name: str (default = \"forces\")\n", + " >Quantity keyword.\n", " \n", - " - reductions: mae, mse\n", - " - Reductions on target-prediction differences.\n" + " - reductions: list of str (default = [mae, mse])\n", + " >Reductions on target-prediction differences.\n" ] }, { @@ -810,29 +666,29 @@ "source": [ "\n", "- **Optimizer**\n", - " - opt_name: adam\n", - " - Optimizer name.\n", + " - opt_name: str (default = \"adam\")\n", + " >Optimizer name. #TODO fill in the other options\n", " \n", - " - opt_kwargs: {}\n", - " - Optimizer keyword arguments.\n", + " - opt_kwargs: dict (if optimizer requires)\n", + " >Optimizer keyword arguments.\n", " \n", - " - emb_lr: 0.03\n", - " - Learning rate for elemental embedding contraction coefficients.\n", + " - emb_lr: float (default = 0.03)\n", + " >Learning rate for elemental embedding contraction coefficients.\n", " \n", - " - nn_lr: 0.03\n", - " - Learning rate for neural network parameters.\n", + " - nn_lr: float (default = 0.03)\n", + " >Learning rate for neural network parameters.\n", " \n", - " - scale_lr: 0.001\n", - " - Learning rate for elemental output scaling factors.\n", + " - scale_lr: float (default = 0.001)\n", + " >Learning rate for elemental output scaling factors.\n", " \n", - " - shift_lr: 0.05\n", - " - Learning rate for elemental output shifts.\n", + " - shift_lr: float (default = 0.05)\n", + " >Learning rate for elemental output shifts.\n", " \n", - " - zbl_lr: 0.001\n", - " - Learning rate for Zero-Body-Loss.\n", + " - zbl_lr: float (default = 0.001)\n", + " >Learning rate for Zero-Body-Loss.\n", " \n", - " - transition_begin: 0\n", - " - Training steps before linear learning rate schedule.\n" + " - transition_begin: int (default = 0)\n", + " >Training steps before linear learning rate schedule.\n" ] }, { @@ -841,8 +697,8 @@ "source": [ "\n", "- **Callbacks**\n", - " - name: csv\n", - " - Callback name.\n" + " - name: str (default = \"csv\") \n", + " >Callback name.\n" ] }, { @@ -851,11 +707,11 @@ "source": [ "\n", "- **Progress Bar**\n", - " - disable_epoch_pbar: false\n", - " - Disable epoch progress bar.\n", + " - disable_epoch_pbar: bool (default = false)\n", + " >Disable epoch progress bar.\n", "\n", - " - disable_nl_pbar: false\n", - " - Disable NL precomputation progress bar.\n" + " - disable_nl_pbar: bool (default = false)\n", + " >Disable NL precomputation progress bar.\n" ] }, { @@ -863,14 +719,14 @@ "metadata": {}, "source": [ "- **Checkpoints**\n", - " - ckpt_interval: 1\n", - " - Epochs between checkpoints.\n", + " - ckpt_interval: int (default = 1)\n", + " >Epochs between checkpoints.\n", " \n", - " - base_model_checkpoint: null\n", - " - Path to pre-trained model checkpoint.\n", + " - base_model_checkpoint: (optional)\n", + " >Path to pre-trained model checkpoint.\n", " \n", - " - reset_layers: []\n", - " - List of layers to reinitialize parameters." + " - reset_layers: (optional)\n", + " >List of layers to reinitialize parameters." ] }, { @@ -882,11 +738,81 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ - "# !rm -r project config.yaml error_config.yaml eval.log" + "# !rm -r project config.yaml eval.log" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Default Value | Description |\n", + "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", + "| **n_epochs** | `` | Number of training epochs. |\n", + "| **seed** | 1 | Seed for initializing random numbers. |\n", + "| **patience** | None | Number of epochs without improvement before training termination. |\n", + "| **n_models** | 1 | Number of models trained simultaneously. |\n", + "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", + "| **Data** | | |\n", + "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", + "| experiment | apax | Model name distinguishing from others in directory. |\n", + "| data_path | `` | Path to single dataset file. |\n", + "| train_data_path | `` | Path to training dataset. |\n", + "| val_data_path | `` | Path to validation dataset. |\n", + "| test_data_path | `` | Path to test dataset. |\n", + "| n_train | 1000 | Number of training data points. |\n", + "| n_valid | 100 | Number of validation data points. |\n", + "| batch_size | 32 | Number of training examples evaluated at once. |\n", + "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", + "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", + "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", + "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", + "| pos_unit | Ang | Positional unit. |\n", + "| energy_unit | eV | Energy unit. |\n", + "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", + "| **Model** | | |\n", + "| n_basis | 7 | Number of Gaussian basis functions. |\n", + "| n_radial | 5 | Number of contracted basis functions. |\n", + "| nn | [512, 512] | Hidden layers and units. |\n", + "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", + "| r_min | 0.5 | Descriptor cutoff radius. |\n", + "| use_zbl | false | Use Zero-Body-Loss. |\n", + "| b_init | normal | Initialization scheme for biases. |\n", + "| descriptor_dtype | fp64 | Descriptor data type. |\n", + "| readout_dtype | fp32 | Readout data type. |\n", + "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", + "| **Loss** | | |\n", + "| loss_type | structures | Weighting scheme for atomic contributions. |\n", + "| name | energy | Quantity keyword. |\n", + "| weight | 1.0 | Weighting factor in loss function. |\n", + "| name | forces | Quantity keyword. |\n", + "| weight | 4.0 | Weighting factor in loss function. |\n", + "| **Metrics** | | |\n", + "| name | energy | Quantity keyword. |\n", + "| reductions | | List of reductions on target-prediction differences. |\n", + "| name | forces | Quantity keyword. |\n", + "| reductions | mae, mse | Reductions on target-prediction differences. |\n", + "| **Optimizer** | | |\n", + "| opt_name | adam | Optimizer name. |\n", + "| opt_kwargs | {} | Optimizer keyword arguments. |\n", + "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", + "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", + "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", + "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", + "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", + "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", + "| **Callbacks** | | |\n", + "| name | csv | Callback name. |\n", + "| **Progress Bar** | | |\n", + "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", + "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", + "| **Checkpoints** | | |\n", + "| ckpt_interval | 1 | Epochs between checkpoints. |\n", + "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", + "| reset_layers | [] | List of layers to reinitialize parameters. |\n" ] } ], From 2ee0aa778eb2f7c838d153bd8faa71afeabc0b96 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:16:13 +0000 Subject: [PATCH 101/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 1b1dba70..8d466bc0 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -46,4 +46,4 @@ def load_csv_metrics(path): key = headers[idx] data_dict[key].append(float(value)) - return data_dict \ No newline at end of file + return data_dict From 74a8de5978de2645bbb07e7dde4f7f8c101a2752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 12 Mar 2024 17:10:52 +0100 Subject: [PATCH 102/192] implemented dataset which does not precompute NL --- apax/data/input_pipeline.py | 220 +++++++++++++++++++++++++++++++++--- apax/data/preprocessing.py | 11 +- apax/data/statistics.py | 16 +-- apax/train/run.py | 19 +++- apax/train/trainer.py | 6 +- 5 files changed, 236 insertions(+), 36 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 6a006ae6..9094d970 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -14,7 +14,7 @@ def find_largest_system(inputs: dict[str, np.ndarray]) -> tuple[int]: max_atoms = np.max(inputs["fixed"]["n_atoms"]) - nbr_shapes = [idx.shape[1] for idx in inputs["ragged"]["idx"]] + nbr_shapes = [idx.shape[1] for idx in inputs["fixed"]["idx"]] # REMOVE max_nbrs = np.max(nbr_shapes) return max_atoms, max_nbrs @@ -61,12 +61,12 @@ def __call__(self, inputs: dict, labels: dict = None) -> tuple[dict, dict]: for key, val in r_inputs.items(): if self.max_atoms is None: r_inputs[key] = val.to_tensor() - elif key == "idx": - shape = r_inputs[key].shape - padded_shape = [shape[0], shape[1], self.max_nbrs] # batch, ij, nbrs - elif key == "offsets": - shape = r_inputs[key].shape - padded_shape = [shape[0], self.max_nbrs, 3] # batch, ij, nbrs + # elif key == "idx": + # shape = r_inputs[key].shape + # padded_shape = [shape[0], shape[1], self.max_nbrs] # batch, ij, nbrs + # elif key == "offsets": + # shape = r_inputs[key].shape + # padded_shape = [shape[0], self.max_nbrs, 3] # batch, ij, nbrs # KILL elif key == "numbers": shape = r_inputs[key].shape padded_shape = [shape[0], self.max_atoms] # batch, atoms @@ -85,6 +85,7 @@ def __call__(self, inputs: dict, labels: dict = None) -> tuple[dict, dict]: if self.max_atoms is None: r_labels[key] = val.to_tensor() else: + shape = r_labels[key].shape padded_shape = [shape[0], self.max_atoms, shape[2]] r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) @@ -96,23 +97,38 @@ def __call__(self, inputs: dict, labels: dict = None) -> tuple[dict, dict]: return new_inputs +def pad_neighborlist(idxs, offsets, max_neighbors): + new_idxs = [] + new_offsets = [] + + for idx, offset in zip(idxs, offsets): + zeros_to_add = max_neighbors - idx.shape[1] + new_idx = np.pad(idx, ((0, 0), (0, zeros_to_add)), "constant").astype(np.int16) + new_offset = np.pad(offset, ((0, zeros_to_add), (0, 0)), "constant").astype(np.int16) + new_idxs.append(new_idx) + new_offsets.append(new_offset) + + return new_idxs, new_offsets + + def process_inputs( atoms_list: list, r_max: float, disable_pbar=False, pos_unit: str = "Ang", ) -> dict: - inputs = atoms_to_inputs(atoms_list, pos_unit) - idx, offsets = dataset_neighborlist( + inputs = atoms_to_inputs(atoms_list, pos_unit) # find largest input + idx, offsets, max_neighbors = dataset_neighborlist( inputs["ragged"]["positions"], - box=inputs["fixed"]["box"], + inputs["fixed"]["box"], r_max=r_max, - atoms_list=atoms_list, disable_pbar=disable_pbar, ) - inputs["ragged"]["idx"] = idx - inputs["ragged"]["offsets"] = offsets + idx, offsets = pad_neighborlist(idx, offsets, max_neighbors) + + inputs["fixed"]["idx"] = idx + inputs["fixed"]["offsets"] = offsets return inputs @@ -141,7 +157,7 @@ def dataset_from_dicts( return ds - +from apax.utils.convert import atoms_to_inputs class AtomisticDataset: """Class processes inputs/labels and makes them accessible for training.""" @@ -246,8 +262,10 @@ def shuffle_and_batch(self) -> Iterator[jax.Array]: Iterator that returns inputs and labels of one batch in each step. """ self._check_batch_size() + #should we shuffle before or after repeat?? ds = ( - self.ds.shuffle(buffer_size=self.buffer_size) + self.ds + .shuffle(buffer_size=self.buffer_size) .repeat(self.n_epoch) .batch(batch_size=self.batch_size) .map(PadToSpecificSize(self.max_atoms, self.max_nbrs)) @@ -267,3 +285,175 @@ def batch(self) -> Iterator[jax.Array]: ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) return ds + + + + +import numpy as np +from collections import deque +from random import shuffle +import tensorflow as tf +from apax.data.preprocessing import compute_nl, prefetch_to_single_device +from apax.utils.convert import atoms_to_inputs, atoms_to_labels + +def pad_nl(idx, offsets, max_neighbors): + zeros_to_add = max_neighbors - idx.shape[1] + idx = np.pad(idx, ((0, 0), (0, zeros_to_add)), "constant").astype(np.int16) + offsets = np.pad(offsets, ((0, zeros_to_add), (0, 0)), "constant") + return idx, offsets + + +def find_largest_system2(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: + max_atoms = np.max(inputs["n_atoms"]) + + max_nbrs = 0 + for position, box in zip(inputs["positions"], inputs["box"]): + neighbor_idxs, _ = compute_nl(position, box, r_max) + n_neighbors = neighbor_idxs.shape[1] + max_nbrs = max(max_nbrs, n_neighbors) + + return max_atoms, max_nbrs + +class Dataset: + def __init__(self, atoms, cutoff, bs, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: + if pre_shuffle: + shuffle(atoms) + self.sample_atoms = atoms[0] + inputs = atoms_to_inputs(atoms) + finputs = {k: v for k,v in inputs["fixed"].items()} + finputs.update({k: v for k,v in inputs["ragged"].items()}) + self.inputs = finputs + + max_atoms, max_nbrs = find_largest_system2(self.inputs, cutoff) + self.max_atoms = max_atoms + self.max_nbrs = max_nbrs + + labels = atoms_to_labels(atoms) + flabels = {k: v for k,v in labels["fixed"].items()} + flabels.update({k: v for k,v in labels["ragged"].items()}) + self.labels = flabels + + self.n_data = len(atoms) + self.count=0 + self.cutoff = cutoff + self.buffer = deque() + self.batch_size = self.validate_batch_size(bs) + self.n_jit_steps = n_jit_steps + self.name = name + + self.buffer_size = 10 + + self.enqueue(self.buffer_size) + + def steps_per_epoch(self) -> int: + """Returns the number of steps per epoch dependent on the number of data and the + batch size. Steps per epoch are calculated in a way that all epochs have the same + number of steps, and all batches have the same length. To do so, some training + data are dropped in each epoch. + """ + return self.n_data // self.batch_size // self.n_jit_steps + + def validate_batch_size(self, batch_size: int) -> int: + if batch_size > self.n_data: + msg = ( + f"requested batch size {batch_size} is larger than the number of data" + f" points {self.n_data}. Setting batch size = {self.n_data}" + ) + print("Warning: " + msg) + log.warning(msg) + batch_size = self.n_data + return batch_size + + def prepare_item(self, i): + inputs = {k:v[i] for k,v in self.inputs.items()} + labels = {k:v[i] for k,v in self.labels.items()} + idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) + inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) + + zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] + inputs["positions"] = np.pad(inputs["positions"], ((0, zeros_to_add), (0, 0)), "constant") + inputs["numbers"] = np.pad(inputs["numbers"], (0, zeros_to_add), "constant").astype(np.int16) + inputs["n_atoms"] = np.pad(inputs["n_atoms"], (0, zeros_to_add), "constant").astype(np.int16) + if "forces" in labels: + labels["forces"] = np.pad(labels["forces"], ((0, zeros_to_add), (0, 0)), "constant") + + inputs = {k:tf.constant(v) for k,v in inputs.items()} + labels = {k:tf.constant(v) for k,v in labels.items()} + return (inputs, labels) + + def enqueue(self, num_elements): + for _ in range(num_elements): + data = self.prepare_item(self.count) + self.buffer.append(data) + self.count += 1 + + def __iter__(self): + while self.count < self.n_data or len(self.buffer) > 0: + yield self.buffer.popleft() + space = self.buffer_size - len(self.buffer) + if self.count + space > self.n_data: + space = self.n_data - self.count + self.enqueue(space) + + def make_signature(self) -> tf.TensorSpec: + input_singature = {} + input_singature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") + input_singature["numbers"] = tf.TensorSpec((self.max_atoms,), dtype=tf.int16, name="numbers") + input_singature["positions"] = tf.TensorSpec((self.max_atoms, 3), dtype=tf.float64, name="positions") + input_singature["box"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="box") + input_singature["idx"] = tf.TensorSpec((2, self.max_nbrs), dtype=tf.int16, name="idx") + input_singature["offsets"] = tf.TensorSpec((self.max_nbrs, 3), dtype=tf.float64, name="offsets") + + label_signature = {} + label_signature + if "energy" in self.labels.keys(): + label_signature["energy"] = tf.TensorSpec((), dtype=tf.float64, name="energy") + if "forces" in self.labels.keys(): + label_signature["forces"] = tf.TensorSpec((self.max_atoms, 3), dtype=tf.float64, name="forces") + if "stress" in self.labels.keys(): + label_signature["stress"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="stress") + signature = (input_singature, label_signature) + return signature + + def init_input(self) -> Dict[str, np.ndarray]: + """Returns first batch of inputs and labels to init the model.""" + positions = self.sample_atoms.positions + box = self.sample_atoms.cell.array + idx, offsets = compute_nl(positions,box, self.cutoff) + inputs = ( + positions, + self.sample_atoms.numbers, + idx, + box, + offsets, + ) + + inputs = jax.tree_map(lambda x: jnp.array(x), inputs) + return inputs, np.array(box) + + def shuffle_and_batch(self): + gen = lambda: self + ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) + + ds = ( + ds + .cache(self.name) + .repeat(10) + .shuffle(buffer_size=100, reshuffle_each_iteration=True) + .batch(batch_size=self.batch_size) + ) + if self.n_jit_steps > 1: + ds = ds.batch(batch_size=self.n_jit_steps) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + return ds + + def batch(self) -> Iterator[jax.Array]: + gen = lambda: self + ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) + ds = (ds + .cache(self.name) + .repeat(10) + .batch(batch_size=self.batch_size) + ) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + return ds \ No newline at end of file diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 8d945e2d..67f67303 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -6,6 +6,7 @@ import jax import jax.numpy as jnp import numpy as np +import tensorflow as tf from ase import Atoms from matscipy.neighbours import neighbour_list from tqdm import trange @@ -37,10 +38,10 @@ def compute_nl(position, box, r_max): "ijS", positions=position, cutoff=r_max, - cell=cell, + cell=box, ) - offsets = np.matmul(offsets, box) neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) + offsets = np.matmul(offsets, box) return neighbor_idxs, offsets @@ -70,6 +71,7 @@ def dataset_neighborlist( # The JaxMD NL throws an error if np arrays are passed to it in the CPU version idx_list = [] offset_list = [] + largest_nl = 0 nl_pbar = trange( len(positions), @@ -81,12 +83,15 @@ def dataset_neighborlist( ) for position, box in zip(positions, boxs): neighbor_idxs, offsets = compute_nl(position, box, r_max) + n_neighbors = neighbor_idxs.shape[1] + largest_nl = max(largest_nl, n_neighbors) + offset_list.append(offsets) idx_list.append(neighbor_idxs) nl_pbar.update() nl_pbar.close() - return idx_list, offset_list + return idx_list, offset_list, largest_nl def get_shrink_wrapped_cell(positions): diff --git a/apax/data/statistics.py b/apax/data/statistics.py index 5a812905..0805f320 100644 --- a/apax/data/statistics.py +++ b/apax/data/statistics.py @@ -23,9 +23,9 @@ def compute(inputs, labels, shift_options) -> np.ndarray: log.info("Computing per element energy regression.") lambd = shift_options["energy_regularisation"] - energies = labels["fixed"]["energy"] - numbers = inputs["ragged"]["numbers"] - system_sizes = inputs["fixed"]["n_atoms"] + energies = labels["energy"] + numbers = inputs["numbers"] + system_sizes = inputs["n_atoms"] energies = np.array(energies) system_sizes = np.array(system_sizes) @@ -80,9 +80,9 @@ class MeanEnergyRMSScale: @staticmethod def compute(inputs, labels, scale_options): # log.info("Computing per element energy regression.") - energies = labels["fixed"]["energy"] - numbers = inputs["ragged"]["numbers"] - system_sizes = inputs["fixed"]["n_atoms"] + energies = labels["energy"] + numbers = inputs["numbers"] + system_sizes = inputs["n_atoms"] energies = np.array(energies) system_sizes = np.array(system_sizes) @@ -111,8 +111,8 @@ class PerElementForceRMSScale: def compute(inputs, labels, scale_options): n_species = 119 - forces = np.concatenate(labels["ragged"]["forces"], axis=0) - numbers = np.concatenate(inputs["ragged"]["numbers"], axis=0) + forces = np.concatenate(labels["forces"], axis=0) + numbers = np.concatenate(inputs["numbers"], axis=0) elements = np.unique(numbers) diff --git a/apax/train/run.py b/apax/train/run.py index a4015f9a..4a36991e 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -6,6 +6,8 @@ from apax.config import LossConfig, parse_config from apax.data.initialization import initialize_dataset, load_data_files +from apax.data.input_pipeline import Dataset +from apax.data.statistics import compute_scale_shift_parameters from apax.model import ModelBuilder from apax.optimizer import get_opt from apax.train.callbacks import initialize_callbacks @@ -31,7 +33,6 @@ def setup_logging(log_file, log_level): while len(logging.root.handlers) > 0: logging.root.removeHandler(logging.root.handlers[-1]) - # Remove uninformative checkpointing absl logs logging.getLogger("absl").setLevel(logging.WARNING) logging.basicConfig( @@ -66,15 +67,21 @@ def run(user_config, log_level="error"): Metrics = initialize_metrics(config.metrics) train_raw_ds, val_raw_ds = load_data_files(config.data) - train_ds, ds_stats = initialize_dataset(config, train_raw_ds) - val_ds = initialize_dataset(config, val_raw_ds, calc_stats=False) - train_ds.set_batch_size(config.data.batch_size) - val_ds.set_batch_size(config.data.valid_batch_size) + train_ds = Dataset(train_raw_ds, config.model.r_max, config.data.batch_size, config.n_jitted_steps, name="train", pre_shuffle=True) + val_ds = Dataset(val_raw_ds, config.model.r_max, config.data.valid_batch_size, name="val") + ds_stats = compute_scale_shift_parameters( + train_ds.inputs, + train_ds.labels, + config.data.shift_method, + config.data.scale_method, + config.data.shift_options, + config.data.scale_options, + ) + # TODO IMPL DELETE FILES log.info("Initializing Model") sample_input, init_box = train_ds.init_input() - builder = ModelBuilder(config.model.get_dict()) model = builder.build_energy_derivative_model( scale=ds_stats.elemental_scale, diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 0c96277b..138efbc0 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -30,7 +30,6 @@ def fit( patience: Optional[int] = None, disable_pbar: bool = False, is_ensemble=False, - n_jitted_steps=1, ): log.info("Beginning Training") callbacks.on_train_begin() @@ -42,7 +41,7 @@ def fit( train_step, val_step = make_step_fns( loss_fn, Metrics, model=state.apply_fn, sam_rho=sam_rho, is_ensemble=is_ensemble ) - if n_jitted_steps > 1: + if train_ds.n_jit_steps > 1: train_step = jax.jit(functools.partial(jax.lax.scan, train_step)) state, start_epoch = load_state(state, latest_dir) @@ -51,13 +50,12 @@ def fit( f"n_epochs <= current epoch from checkpoint ({n_epochs} <= {start_epoch})" ) - train_ds.batch_multiple_steps(n_jitted_steps) train_steps_per_epoch = train_ds.steps_per_epoch() batch_train_ds = train_ds.shuffle_and_batch() if val_ds is not None: val_steps_per_epoch = val_ds.steps_per_epoch() - batch_val_ds = val_ds.shuffle_and_batch() + batch_val_ds = val_ds.batch() best_loss = np.inf early_stopping_counter = 0 From af1eee4c4b0d0f17b97ffb0f47006ac6b283085e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 12 Mar 2024 18:06:15 +0100 Subject: [PATCH 103/192] fixed bug when buffer size was larger dataset size --- apax/data/input_pipeline.py | 3 ++- apax/train/run.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 9094d970..2ad33b1f 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -343,7 +343,7 @@ def __init__(self, atoms, cutoff, bs, n_jit_steps= 1, name="train", pre_shuffle= self.buffer_size = 10 - self.enqueue(self.buffer_size) + self.enqueue(min(self.buffer_size, self.n_data)) def steps_per_epoch(self) -> int: """Returns the number of steps per epoch dependent on the number of data and the @@ -393,6 +393,7 @@ def __iter__(self): space = self.buffer_size - len(self.buffer) if self.count + space > self.n_data: space = self.n_data - self.count + print(self.count, space) self.enqueue(space) def make_signature(self) -> tf.TensorSpec: diff --git a/apax/train/run.py b/apax/train/run.py index 4a36991e..d07011ae 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -124,5 +124,4 @@ def run(user_config, log_level="error"): patience=config.patience, disable_pbar=config.progress_bar.disable_epoch_pbar, is_ensemble=config.n_models > 1, - n_jitted_steps=config.n_jitted_steps, ) From ff65ee4f24fb2400cab5b911b13ee70bc7869539 Mon Sep 17 00:00:00 2001 From: Nico Segreto Date: Wed, 13 Mar 2024 14:13:24 +0100 Subject: [PATCH 104/192] Update io.py --- apax/md/io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/md/io.py b/apax/md/io.py index 19b29c4b..8f783a0a 100644 --- a/apax/md/io.py +++ b/apax/md/io.py @@ -50,7 +50,7 @@ def atoms_from_state(self, state, energy, nbr_kwargs): atoms = Atoms(self.atomic_numbers, positions, momenta=momenta, cell=box) atoms.cell = atoms.cell.T - atoms.pbc = np.diag(atoms.cell.array) > 1e-7 + atoms.pbc = np.diag(atoms.cell.array) > 1e-6 atoms.calc = SinglePointCalculator(atoms, energy=float(energy), forces=forces) return atoms @@ -66,7 +66,7 @@ def __init__( ) -> None: self.atomic_numbers = system.atomic_numbers self.box = system.box - self.fractional = np.any(self.box < 1e-6) + self.fractional = np.any(self.box > 1e-6) self.sampling_rate = sampling_rate self.traj_path = traj_path self.db = znh5md.io.DataWriter(self.traj_path) From 421464eedde3d781760c505d809196107ebbcadb Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 15 Mar 2024 11:34:55 +0100 Subject: [PATCH 105/192] fix: fractional coords in nvt MD --- apax/md/nvt.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apax/md/nvt.py b/apax/md/nvt.py index 6ee02196..87014987 100644 --- a/apax/md/nvt.py +++ b/apax/md/nvt.py @@ -339,8 +339,10 @@ def md_setup(model_config: Config, md_config: MDConfig): r_max = model_config.model.r_max log.info("initializing model") if np.all(system.box < 1e-6): + frac_coords = False displacement_fn, shift_fn = space.free() else: + frac_coords = True heights = heights_of_box_sides(system.box) if np.any(atoms.cell.lengths() / 2 < r_max): @@ -356,7 +358,7 @@ def md_setup(model_config: Config, md_config: MDConfig): "can not calculate the correct neighbors", ) displacement_fn, shift_fn = space.periodic_general( - system.box, fractional_coordinates=True + system.box, fractional_coordinates=frac_coords ) builder = ModelBuilder(model_config.model.get_dict()) @@ -368,7 +370,7 @@ def md_setup(model_config: Config, md_config: MDConfig): system.box, r_max, md_config.dr_threshold, - fractional_coordinates=True, + fractional_coordinates=frac_coords, format=partition.Sparse, disable_cell_list=True, ) From f58591a54d0e1aa31e15862505facdffc5181034 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Fri, 15 Mar 2024 11:36:38 +0100 Subject: [PATCH 106/192] update: examples --- examples/01_Model_Training.ipynb | 330 +-------------------------- examples/02_Molecular_Dynamics.ipynb | 185 ++++++++++----- examples/05_Full_Config.ipynb | 328 ++++++++++++++++++++++++++ 3 files changed, 453 insertions(+), 390 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index d640a0db..48248ffc 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -98,7 +98,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The following command create a minimal configuration file in the working directory." + "The following command create a minimal configuration file in the working directory. Full configuration file with descriptiond of the prameter can be found [here](./05_Full_Config.ipynb)." ] }, { @@ -471,264 +471,6 @@ "## A Closer Look At Training Parameters" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", - "\n", - "- **n_epochs**: int (required)\n", - "\n", - " >Number of training epochs.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **seed**: int (default = 1)\n", - " \n", - " >Seed for initializing random numbers.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **patience**: int (optional)\n", - "\n", - " >Number of epochs without improvement before training termination.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **n_models**: int (default = 1)\n", - "\n", - " >Number of models trained simultaneously.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **n_jitted_steps**: int (default = 1)\n", - "\n", - " >Number of train batches in a compiled loop. Can speed up for small batches." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Data**\n", - " - directory: str (default = \"/models\")\n", - "\n", - " >Path to directory where training results and checkpoints are written.\n", - "\n", - "\n", - " - experiment: str (default = \"apax\")\n", - "\n", - " >Model name distinguishing from others in directory. \n", - "\n", - "\n", - " - data_path: str (required if train_ and val_data_path is not specified)\n", - "\n", - " >Path to single dataset file.\n", - " \n", - "\n", - " - train_data_path: str (required if data_path is not specified)\n", - " >Path to training dataset.\n", - "\n", - " - val_data_path: str (required if data_path is not specified)\n", - " >Path to validation dataset.\n", - "\n", - " - test_data_path: str (optional)\n", - " >Path to test dataset.\n", - "\n", - " - n_train: int (default = 1000)\n", - " >Number of training data points.\n", - " \n", - " - n_valid: int (default = 100)\n", - " >Number of validation data points.\n", - " \n", - " - batch_size: int (default = 32)\n", - " >Number of training examples evaluated at once.\n", - " \n", - " - valid_batch_size: int (default = 100)\n", - " >Number of validation examples evaluated at once.\n", - " \n", - " - shift_method: str (default = \"per_element_regression_shift\")\n", - " >Method for shifting.\n", - " \n", - " - shift_options: dict (default = {\"energy_regularization\": 1.0})\n", - " >Regularization magnitude for energy regression. #TODO fill in the other options\n", - " \n", - " - shuffle_buffer_size: int (default = 1000)\n", - " >Size of `tf.data` shuffle buffer.\n", - " \n", - " - pos_unit: str (default = \"Ang\")\n", - " >Positional unit.\n", - " \n", - " - energy_unit: str (default = \"eV\")\n", - " >Energy unit.\n", - " \n", - " - additional_properties_info: dict (optional)\n", - " >Dictionary of property name, shape pairs.\n", - " \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Model**\n", - " - n_basis: int (default = 7)\n", - " >Number of Gaussian basis functions.\n", - "\n", - " - n_radial: int (default = 5)\n", - " >Number of contracted basis functions.\n", - "\n", - " - nn: list of int (default = [512, 512])\n", - " >Hidden layers and units.\n", - "\n", - " - r_max: float (default = 6.0)\n", - " >Maximum position of first basis function's mean in angstrom.\n", - "\n", - " - r_min: float (default = 0.5)\n", - " >Descriptor cutoff radius in angstrom.\n", - "\n", - " - use_zbl: bool (default = false)\n", - " >Use emperical Ziegler-Biersack-Littmark potential.\n", - "\n", - " - b_init: str (default = \"normal\")\n", - " >Initialization scheme for biases. #TODO fill in the other options\n", - "\n", - " - descriptor_dtype: str (default = \"fp64\")\n", - " >Descriptor data type.\n", - "\n", - " - readout_dtype: str (default = \"fp32\")\n", - " >Readout data type.\n", - "\n", - " - scale_shift_dtype: str (default = \"fp32\")\n", - " >Scale/Shift data type.\n", - " \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Loss**\n", - " - loss_type: str (default = \"structures\")\n", - " >Weighting scheme for atomic contributions. #TODO fill in the other options\n", - "\n", - " - name: str (default = \"energy\")\n", - " >Quantity keyword.\n", - "\n", - " - weight: float (default = 1.0)\n", - " >Weighting factor in loss function.\n", - "\n", - " - name: str (default = \"forces\")\n", - " >Quantity keyword.\n", - "\n", - " - weight: float (default = 4.0)\n", - " >Weighting factor in loss function." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Metrics**\n", - " - name: str (default = \"energy\")\n", - " >Quantity keyword.\n", - " \n", - " - reductions:\n", - " >List of reductions on target-prediction differences.\n", - " \n", - " - name: str (default = \"forces\")\n", - " >Quantity keyword.\n", - " \n", - " - reductions: list of str (default = [mae, mse])\n", - " >Reductions on target-prediction differences.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Optimizer**\n", - " - opt_name: str (default = \"adam\")\n", - " >Optimizer name. #TODO fill in the other options\n", - " \n", - " - opt_kwargs: dict (if optimizer requires)\n", - " >Optimizer keyword arguments.\n", - " \n", - " - emb_lr: float (default = 0.03)\n", - " >Learning rate for elemental embedding contraction coefficients.\n", - " \n", - " - nn_lr: float (default = 0.03)\n", - " >Learning rate for neural network parameters.\n", - " \n", - " - scale_lr: float (default = 0.001)\n", - " >Learning rate for elemental output scaling factors.\n", - " \n", - " - shift_lr: float (default = 0.05)\n", - " >Learning rate for elemental output shifts.\n", - " \n", - " - zbl_lr: float (default = 0.001)\n", - " >Learning rate for Zero-Body-Loss.\n", - " \n", - " - transition_begin: int (default = 0)\n", - " >Training steps before linear learning rate schedule.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Callbacks**\n", - " - name: str (default = \"csv\") \n", - " >Callback name.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Progress Bar**\n", - " - disable_epoch_pbar: bool (default = false)\n", - " >Disable epoch progress bar.\n", - "\n", - " - disable_nl_pbar: bool (default = false)\n", - " >Disable NL precomputation progress bar.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Checkpoints**\n", - " - ckpt_interval: int (default = 1)\n", - " >Epochs between checkpoints.\n", - " \n", - " - base_model_checkpoint: (optional)\n", - " >Path to pre-trained model checkpoint.\n", - " \n", - " - reset_layers: (optional)\n", - " >List of layers to reinitialize parameters." - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -744,76 +486,6 @@ "source": [ "# !rm -r project config.yaml eval.log" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Parameter | Default Value | Description |\n", - "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", - "| **n_epochs** | `` | Number of training epochs. |\n", - "| **seed** | 1 | Seed for initializing random numbers. |\n", - "| **patience** | None | Number of epochs without improvement before training termination. |\n", - "| **n_models** | 1 | Number of models trained simultaneously. |\n", - "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", - "| **Data** | | |\n", - "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", - "| experiment | apax | Model name distinguishing from others in directory. |\n", - "| data_path | `` | Path to single dataset file. |\n", - "| train_data_path | `` | Path to training dataset. |\n", - "| val_data_path | `` | Path to validation dataset. |\n", - "| test_data_path | `` | Path to test dataset. |\n", - "| n_train | 1000 | Number of training data points. |\n", - "| n_valid | 100 | Number of validation data points. |\n", - "| batch_size | 32 | Number of training examples evaluated at once. |\n", - "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", - "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", - "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", - "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", - "| pos_unit | Ang | Positional unit. |\n", - "| energy_unit | eV | Energy unit. |\n", - "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", - "| **Model** | | |\n", - "| n_basis | 7 | Number of Gaussian basis functions. |\n", - "| n_radial | 5 | Number of contracted basis functions. |\n", - "| nn | [512, 512] | Hidden layers and units. |\n", - "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", - "| r_min | 0.5 | Descriptor cutoff radius. |\n", - "| use_zbl | false | Use Zero-Body-Loss. |\n", - "| b_init | normal | Initialization scheme for biases. |\n", - "| descriptor_dtype | fp64 | Descriptor data type. |\n", - "| readout_dtype | fp32 | Readout data type. |\n", - "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", - "| **Loss** | | |\n", - "| loss_type | structures | Weighting scheme for atomic contributions. |\n", - "| name | energy | Quantity keyword. |\n", - "| weight | 1.0 | Weighting factor in loss function. |\n", - "| name | forces | Quantity keyword. |\n", - "| weight | 4.0 | Weighting factor in loss function. |\n", - "| **Metrics** | | |\n", - "| name | energy | Quantity keyword. |\n", - "| reductions | | List of reductions on target-prediction differences. |\n", - "| name | forces | Quantity keyword. |\n", - "| reductions | mae, mse | Reductions on target-prediction differences. |\n", - "| **Optimizer** | | |\n", - "| opt_name | adam | Optimizer name. |\n", - "| opt_kwargs | {} | Optimizer keyword arguments. |\n", - "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", - "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", - "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", - "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", - "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", - "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", - "| **Callbacks** | | |\n", - "| name | csv | Callback name. |\n", - "| **Progress Bar** | | |\n", - "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", - "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", - "| **Checkpoints** | | |\n", - "| ckpt_interval | 1 | Epochs between checkpoints. |\n", - "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", - "| reset_layers | [] | List of layers to reinitialize parameters. |\n" - ] } ], "metadata": { diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index 75b8dc63..1c9ad821 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -49,15 +49,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|███████████████████████████████████████| 1000/1000 [00:00<00:00, 12924.12it/s]\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 100/100 [00:00<00:00, 11632.43it/s]\n", - "Epochs: 100%|██████████████████████████████████████| 100/100 [03:36<00:00, 2.17s/it, val_loss=0.31]\n" + "2024-03-13 13:23:46.912545: W external/xla/xla/service/gpu/nvptx_compiler.cc:742] The NVIDIA driver's CUDA version is 11.4 which is older than the ptxas CUDA version (11.8.89). Because the driver is older than the ptxas version, XLA is disabling parallel compilation, which may slow down compilation. You should update your NVIDIA driver or use the NVIDIA-provided CUDA forward compatibility packages.\n", + "Precomputing NL: 100%|█████████████████████████████████████████| 990/990 [00:00<00:00, 23520.26it/s]\n", + "Precomputing NL: 100%|███████████████████████████████████████████| 10/10 [00:00<00:00, 10260.04it/s]\n", + "Epochs: 100%|████████████████████████████████████| 100/100 [00:47<00:00, 2.10it/s, val_loss=0.0693]\n" ] } ], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_benzene_DFT, mod_md_datasets\n", + "from apax.utils.datasets import download_etoh_ccsdt, mod_md_datasets\n", "from apax.train.run import run\n", "from apax.utils.helpers import mod_config\n", "import yaml\n", @@ -65,10 +66,12 @@ "\n", "# Download and modify the dataset\n", "data_path = Path(\"project\")\n", - "experiment = \"benzene_md\"\n", + "experiment = \"etoh_md\"\n", "\n", - "file_path = download_benzene_DFT(data_path)\n", - "file_path = mod_md_datasets(file_path)\n", + "\n", + "train_file_path, test_file_path = download_etoh_ccsdt(data_path)\n", + "train_file_path = mod_md_datasets(train_file_path)\n", + "test_file_path = mod_md_datasets(test_file_path)\n", "\n", "\n", "# Modify the config file (can be done manually)\n", @@ -77,21 +80,24 @@ "config_updates = {\n", " \"n_epochs\": 100,\n", " \"data\": {\n", + " \"n_train\": 990,\n", + " \"n_valid\": 10,\n", + " \"valid_batch_size\": 1,\n", " \"experiment\": experiment,\n", - " \"directory\": str(data_path / \"models\"),\n", - " \"data_path\": str(file_path),\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(train_file_path),\n", + " \"test_data_path\": str(test_file_path),\n", " \"energy_unit\": \"kcal/mol\",\n", " \"pos_unit\": \"Ang\",\n", - " }\n", + " },\n", + " \"model\": {\n", + " \"descriptor_dtype\": \"fp64\"\n", + " },\n", "}\n", "config_dict = mod_config(config_path, config_updates)\n", - "\n", - "\n", - "# dump config for cli showcase\n", "with open(\"config.yaml\", \"w\") as conf:\n", " yaml.dump(config_dict, conf, default_flow_style=False)\n", "\n", - "\n", "# Train model\n", "run(config_dict)\n" ] @@ -106,7 +112,7 @@ "\n", "Please refer to the [ASE documentation](https://wiki.fysik.dtu.dk/ase/ase/calculators/calculators.html) to see how to use ASE calculators.\n", "\n", - "An ASE calculator of a trained model can be instantiated as follows." + "An ASE calculator of a trained model can be instantiated as follows. Subsequend a ASE-MD is performed and OH-bondlength distribution is analysed." ] }, { @@ -119,12 +125,11 @@ "from apax.md import ASECalculator\n", "from ase.md.langevin import Langevin\n", "from ase import units\n", - "import numpy as np\n", "from ase.io.trajectory import Trajectory\n", "\n", "\n", "# read starting structure and define modelpath\n", - "atoms = read(file_path, index=0)\n", + "atoms = read(train_file_path, index=0)\n", "model_dir = data_path / f\"models/{experiment}\"\n", "\n", "\n", @@ -132,7 +137,6 @@ "calc = ASECalculator(model_dir=model_dir)\n", "atoms.calc = calc\n", "\n", - "\n", "# perform MD simulation\n", "dyn = Langevin(\n", " atoms=atoms,\n", @@ -142,11 +146,59 @@ ")\n", "\n", "traj = Trajectory('example.traj', 'w', atoms)\n", - "dyn.attach(traj.write, interval=100)\n", - "dyn.run(1000)\n", + "dyn.attach(traj.write, interval=1)\n", + "dyn.run(10000)\n", "traj.close()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "def plot_bondlength_distribution(traj, indices: list, bins: int=25):\n", + " oh_dist = []\n", + " for atoms in traj:\n", + " oh_dist.append(atoms.get_distances(indices[0], indices[1]))\n", + "\n", + " fig, axs = plt.subplots()\n", + " axs.hist(np.array(oh_dist), bins=25)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot OH bondlength distribution of the MLMD simulation\n", + "traj = Trajectory('example.traj')\n", + "plot_bondlength_distribution(traj, indices=[2, -1])\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -159,7 +211,7 @@ "The CLI provides easy access to standard NVT and NPT simulations.\n", "More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). \n", "Trained apax models can of course be used as `energy_fn` in such custom simulations.\n", - "If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on Github LINK.\n" + "If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on [Github]{https://github.com/apax-hub/apax}.\n" ] }, { @@ -172,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -199,7 +251,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -207,18 +259,18 @@ "import yaml\n", "\n", "\n", - "config_path = Path(\"md_config.yaml\")\n", + "md_config_path = Path(\"md_config.yaml\")\n", "\n", "config_updates = {\n", - " \"initial_structure\": str(file_path), # if the model from example 01 is used change this\n", - " \"duration\": 1000, #fs\n", + " \"initial_structure\": str(train_file_path), # if the model from example 01 is used change this\n", + " \"duration\": 5000, #fs\n", " \"ensemble\": {\n", " \"temperature\": 300,\n", " }\n", "}\n", - "config_dict = mod_config(config_path, config_updates)\n", + "config_dict = mod_config(md_config_path, config_updates)\n", "\n", - "with open(\"md_config.yaml\", \"w\") as conf:\n", + "with open(md_config_path, \"w\") as conf:\n", " yaml.dump(config_dict, conf, default_flow_style=False)" ] }, @@ -232,7 +284,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -254,65 +306,76 @@ "source": [ "## Running the simulation\n", "\n", - "The simulation can be started by running" + "The simulation can be started by running where `config.yaml` is the configuration file that was used to train the model." ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "INFO | 12:39:38 | reading structure\n", - "INFO | 12:39:39 | Unable to initialize backend 'cuda': \n", - "INFO | 12:39:39 | Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n", - "INFO | 12:39:39 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", - "INFO | 12:39:39 | initializing model\n", - "INFO | 12:39:39 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/benzene_md/best\n", - "INFO | 12:39:39 | Initializing new trajectory file at md/md.h5\n", - "INFO | 12:39:39 | initializing simulation\n", - "INFO | 12:39:41 | running simulation for 1.0 ps\n", - "Simulation: 100%|███████████████████████████████████| 2000/2000 [00:10<00:00, 183.72it/s, T=196.3 K]\n", - "INFO | 12:39:52 | simulation finished after elapsed time: 10.93 s\n" + "INFO | 13:39:53 | reading structure\n", + "INFO | 13:39:53 | Unable to initialize backend 'rocm': NOT_FOUND: Could not find registered platform with name: \"rocm\". Available platform names are: CUDA\n", + "INFO | 13:39:53 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", + "2024-03-13 13:39:54.071387: W external/xla/xla/service/gpu/nvptx_compiler.cc:742] The NVIDIA driver's CUDA version is 11.4 which is older than the ptxas CUDA version (11.8.89). Because the driver is older than the ptxas version, XLA is disabling parallel compilation, which may slow down compilation. You should update your NVIDIA driver or use the NVIDIA-provided CUDA forward compatibility packages.\n", + "INFO | 13:39:54 | initializing model\n", + "INFO | 13:39:54 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/etoh_md/best\n", + "INFO | 13:39:54 | Initializing new trajectory file at md/md.h5\n", + "INFO | 13:39:54 | initializing simulation\n", + "INFO | 13:39:57 | running simulation for 5.0 ps\n", + "Simulation: 0%| | 0/10000 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "### Observables\n", + "import znh5md\n", "\n", - "TODO" + "atoms = znh5md.ASEH5MD(\"md/md.h5\").get_atoms_list()\n", + "print(atoms[0].numbers)\n", + "plot_bondlength_distribution(atoms, indices=[2, -1])" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -322,11 +385,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ - "!rm -r project md config.yaml example.traj md_config.yaml" + "# !rm -rf project md config.yaml example.traj md_config.yaml" ] }, { diff --git a/examples/05_Full_Config.ipynb b/examples/05_Full_Config.ipynb index 64135e3b..8dc92ed1 100644 --- a/examples/05_Full_Config.ipynb +++ b/examples/05_Full_Config.ipynb @@ -1,5 +1,333 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", + "\n", + "- **n_epochs**: int (required)\n", + "\n", + " >Number of training epochs.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **seed**: int (default = 1)\n", + " \n", + " >Seed for initializing random numbers.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **patience**: int (optional)\n", + "\n", + " >Number of epochs without improvement before training termination.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_models**: int (default = 1)\n", + "\n", + " >Number of models trained simultaneously.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **n_jitted_steps**: int (default = 1)\n", + "\n", + " >Number of train batches in a compiled loop. Can speed up for small batches." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Data**\n", + " - directory: str (default = \"/models\")\n", + "\n", + " >Path to directory where training results and checkpoints are written.\n", + "\n", + "\n", + " - experiment: str (default = \"apax\")\n", + "\n", + " >Model name distinguishing from others in directory. \n", + "\n", + "\n", + " - data_path: str (required if train_ and val_data_path is not specified)\n", + "\n", + " >Path to single dataset file.\n", + " \n", + "\n", + " - train_data_path: str (required if data_path is not specified)\n", + " >Path to training dataset.\n", + "\n", + " - val_data_path: str (required if data_path is not specified)\n", + " >Path to validation dataset.\n", + "\n", + " - test_data_path: str (optional)\n", + " >Path to test dataset.\n", + "\n", + " - n_train: int (default = 1000)\n", + " >Number of training data points.\n", + " \n", + " - n_valid: int (default = 100)\n", + " >Number of validation data points.\n", + " \n", + " - batch_size: int (default = 32)\n", + " >Number of training examples evaluated at once.\n", + " \n", + " - valid_batch_size: int (default = 100)\n", + " >Number of validation examples evaluated at once.\n", + " \n", + " - shift_method: str (default = \"per_element_regression_shift\")\n", + " >Method for shifting.\n", + " \n", + " - shift_options: dict (default = {\"energy_regularization\": 1.0})\n", + " >Regularization magnitude for energy regression. #TODO fill in the other options\n", + " \n", + " - shuffle_buffer_size: int (default = 1000)\n", + " >Size of `tf.data` shuffle buffer.\n", + " \n", + " - pos_unit: str (default = \"Ang\")\n", + " >Positional unit.\n", + " \n", + " - energy_unit: str (default = \"eV\")\n", + " >Energy unit.\n", + " \n", + " - additional_properties_info: dict (optional)\n", + " >Dictionary of property name, shape pairs.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Model**\n", + " - n_basis: int (default = 7)\n", + " >Number of Gaussian basis functions.\n", + "\n", + " - n_radial: int (default = 5)\n", + " >Number of contracted basis functions.\n", + "\n", + " - nn: list of int (default = [512, 512])\n", + " >Hidden layers and units.\n", + "\n", + " - r_max: float (default = 6.0)\n", + " >Maximum position of first basis function's mean in angstrom.\n", + "\n", + " - r_min: float (default = 0.5)\n", + " >Descriptor cutoff radius in angstrom.\n", + "\n", + " - use_zbl: bool (default = false)\n", + " >Use emperical Ziegler-Biersack-Littmark potential.\n", + "\n", + " - b_init: str (default = \"normal\")\n", + " >Initialization scheme for biases. #TODO fill in the other options\n", + "\n", + " - descriptor_dtype: str (default = \"fp64\")\n", + " >Descriptor data type.\n", + "\n", + " - readout_dtype: str (default = \"fp32\")\n", + " >Readout data type.\n", + "\n", + " - scale_shift_dtype: str (default = \"fp32\")\n", + " >Scale/Shift data type.\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Loss**\n", + " - loss_type: str (default = \"structures\")\n", + " >Weighting scheme for atomic contributions. #TODO fill in the other options\n", + "\n", + " - name: str (default = \"energy\")\n", + " >Quantity keyword.\n", + "\n", + " - weight: float (default = 1.0)\n", + " >Weighting factor in loss function.\n", + "\n", + " - name: str (default = \"forces\")\n", + " >Quantity keyword.\n", + "\n", + " - weight: float (default = 4.0)\n", + " >Weighting factor in loss function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Metrics**\n", + " - name: str (default = \"energy\")\n", + " >Quantity keyword.\n", + " \n", + " - reductions:\n", + " >List of reductions on target-prediction differences.\n", + " \n", + " - name: str (default = \"forces\")\n", + " >Quantity keyword.\n", + " \n", + " - reductions: list of str (default = [mae, mse])\n", + " >Reductions on target-prediction differences.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Optimizer**\n", + " - opt_name: str (default = \"adam\")\n", + " >Optimizer name. #TODO fill in the other options\n", + " \n", + " - opt_kwargs: dict (if optimizer requires)\n", + " >Optimizer keyword arguments.\n", + " \n", + " - emb_lr: float (default = 0.03)\n", + " >Learning rate for elemental embedding contraction coefficients.\n", + " \n", + " - nn_lr: float (default = 0.03)\n", + " >Learning rate for neural network parameters.\n", + " \n", + " - scale_lr: float (default = 0.001)\n", + " >Learning rate for elemental output scaling factors.\n", + " \n", + " - shift_lr: float (default = 0.05)\n", + " >Learning rate for elemental output shifts.\n", + " \n", + " - zbl_lr: float (default = 0.001)\n", + " >Learning rate for Zero-Body-Loss.\n", + " \n", + " - transition_begin: int (default = 0)\n", + " >Training steps before linear learning rate schedule.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Callbacks**\n", + " - name: str (default = \"csv\") \n", + " >Callback name.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "- **Progress Bar**\n", + " - disable_epoch_pbar: bool (default = false)\n", + " >Disable epoch progress bar.\n", + "\n", + " - disable_nl_pbar: bool (default = false)\n", + " >Disable NL precomputation progress bar.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Checkpoints**\n", + " - ckpt_interval: int (default = 1)\n", + " >Epochs between checkpoints.\n", + " \n", + " - base_model_checkpoint: (optional)\n", + " >Path to pre-trained model checkpoint.\n", + " \n", + " - reset_layers: (optional)\n", + " >List of layers to reinitialize parameters." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Default Value | Description |\n", + "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", + "| **n_epochs** | `` | Number of training epochs. |\n", + "| **seed** | 1 | Seed for initializing random numbers. |\n", + "| **patience** | None | Number of epochs without improvement before training termination. |\n", + "| **n_models** | 1 | Number of models trained simultaneously. |\n", + "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", + "| **Data** | | |\n", + "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", + "| experiment | apax | Model name distinguishing from others in directory. |\n", + "| data_path | `` | Path to single dataset file. |\n", + "| train_data_path | `` | Path to training dataset. |\n", + "| val_data_path | `` | Path to validation dataset. |\n", + "| test_data_path | `` | Path to test dataset. |\n", + "| n_train | 1000 | Number of training data points. |\n", + "| n_valid | 100 | Number of validation data points. |\n", + "| batch_size | 32 | Number of training examples evaluated at once. |\n", + "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", + "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", + "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", + "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", + "| pos_unit | Ang | Positional unit. |\n", + "| energy_unit | eV | Energy unit. |\n", + "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", + "| **Model** | | |\n", + "| n_basis | 7 | Number of Gaussian basis functions. |\n", + "| n_radial | 5 | Number of contracted basis functions. |\n", + "| nn | [512, 512] | Hidden layers and units. |\n", + "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", + "| r_min | 0.5 | Descriptor cutoff radius. |\n", + "| use_zbl | false | Use Zero-Body-Loss. |\n", + "| b_init | normal | Initialization scheme for biases. |\n", + "| descriptor_dtype | fp64 | Descriptor data type. |\n", + "| readout_dtype | fp32 | Readout data type. |\n", + "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", + "| **Loss** | | |\n", + "| loss_type | structures | Weighting scheme for atomic contributions. |\n", + "| name | energy | Quantity keyword. |\n", + "| weight | 1.0 | Weighting factor in loss function. |\n", + "| name | forces | Quantity keyword. |\n", + "| weight | 4.0 | Weighting factor in loss function. |\n", + "| **Metrics** | | |\n", + "| name | energy | Quantity keyword. |\n", + "| reductions | | List of reductions on target-prediction differences. |\n", + "| name | forces | Quantity keyword. |\n", + "| reductions | mae, mse | Reductions on target-prediction differences. |\n", + "| **Optimizer** | | |\n", + "| opt_name | adam | Optimizer name. |\n", + "| opt_kwargs | {} | Optimizer keyword arguments. |\n", + "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", + "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", + "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", + "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", + "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", + "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", + "| **Callbacks** | | |\n", + "| name | csv | Callback name. |\n", + "| **Progress Bar** | | |\n", + "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", + "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", + "| **Checkpoints** | | |\n", + "| ckpt_interval | 1 | Epochs between checkpoints. |\n", + "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", + "| reset_layers | [] | List of layers to reinitialize parameters. |\n" + ] + }, { "cell_type": "markdown", "metadata": {}, From 56eba3b12ee37b3032a9cbc6e0e799e22c5be33c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:44:41 +0000 Subject: [PATCH 107/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/datasets.py | 1 + apax/utils/helpers.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 788df425..6e708c4d 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -52,6 +52,7 @@ def download_etoh_ccsdt(data_path): return train_file_path, test_file_path + def download_md22_benzene_CCSDT(data_path): url = "http://www.quantum-machine.org/gdml/data/xyz/benzene_ccsd_t.zip" file_path = data_path / "benzene_ccsdt.zip" diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index 8d466bc0..e3a0ee64 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -1,6 +1,7 @@ import yaml import csv + def setup_ase(): """Add uncertainty keys to ASE all properties. from https://github.com/zincware/IPSuite/blob/main/ipsuite/utils/helpers.py#L10 @@ -30,7 +31,7 @@ def mod_config(config_path, updated_config): def load_csv_metrics(path): data_dict = {} - with open(path, 'r') as file: + with open(path, "r") as file: reader = csv.reader(file) # Extract the headers (keys) from the first row From 91784978d083b6217c51644737c7206682e1fecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 18 Mar 2024 11:29:11 +0100 Subject: [PATCH 108/192] added docstrings --- apax/data/input_pipeline.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 2ad33b1f..889aad87 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -315,7 +315,7 @@ def find_largest_system2(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: return max_atoms, max_nbrs class Dataset: - def __init__(self, atoms, cutoff, bs, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: + def __init__(self, atoms, cutoff, bs, n_epochs, buffer_size, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: if pre_shuffle: shuffle(atoms) self.sample_atoms = atoms[0] @@ -324,6 +324,9 @@ def __init__(self, atoms, cutoff, bs, n_jit_steps= 1, name="train", pre_shuffle= finputs.update({k: v for k,v in inputs["ragged"].items()}) self.inputs = finputs + self.n_epochs = n_epochs + self.buffer_size = buffer_size + max_atoms, max_nbrs = find_largest_system2(self.inputs, cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs @@ -393,7 +396,6 @@ def __iter__(self): space = self.buffer_size - len(self.buffer) if self.count + space > self.n_data: space = self.n_data - self.count - print(self.count, space) self.enqueue(space) def make_signature(self) -> tf.TensorSpec: @@ -433,14 +435,22 @@ def init_input(self) -> Dict[str, np.ndarray]: return inputs, np.array(box) def shuffle_and_batch(self): + """Shuffles and batches the inputs/labels. This function prepares the + inputs and labels for the whole training and prefetches the data. + + Returns + ------- + ds : + Iterator that returns inputs and labels of one batch in each step. + """ gen = lambda: self ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) ds = ( ds .cache(self.name) - .repeat(10) - .shuffle(buffer_size=100, reshuffle_each_iteration=True) + .repeat(self.n_epochs) + .shuffle(buffer_size=self.buffer_size, reshuffle_each_iteration=True) .batch(batch_size=self.batch_size) ) if self.n_jit_steps > 1: @@ -453,8 +463,14 @@ def batch(self) -> Iterator[jax.Array]: ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) ds = (ds .cache(self.name) - .repeat(10) + .repeat(self.n_epochs) .batch(batch_size=self.batch_size) ) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) - return ds \ No newline at end of file + return ds + + def cleanup(self): + """Removes cache files from disk. + Used after training + """ + pass \ No newline at end of file From 986315401017cc20240dc7015e9fc54acb584602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 18 Mar 2024 15:47:29 +0100 Subject: [PATCH 109/192] successfull sharding sketch --- apax/__init__.py | 20 ++++++++++++++++++++ apax/data/input_pipeline.py | 16 ++++++++-------- apax/data/preprocessing.py | 8 ++++++-- apax/train/trainer.py | 17 +++++++++++++++-- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/apax/__init__.py b/apax/__init__.py index 7438bf4a..4fd5cdb2 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -1,5 +1,25 @@ import os +# Set this to True to run the model on CPU only. +USE_CPU_ONLY = True + +flags = os.environ.get("XLA_FLAGS", "") +if USE_CPU_ONLY: + flags += " --xla_force_host_platform_device_count=2" # Simulate 8 devices + # Enforce CPU-only execution + os.environ["CUDA_VISIBLE_DEVICES"] = "" +else: + # GPU flags + flags += ( + "--xla_gpu_enable_triton_softmax_fusion=true " + "--xla_gpu_triton_gemm_any=false " + "--xla_gpu_enable_async_collectives=true " + "--xla_gpu_enable_latency_hiding_scheduler=true " + "--xla_gpu_enable_highest_priority_async_stream=true " + ) +os.environ["XLA_FLAGS"] = flags + + import jax os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 889aad87..1f4db7e7 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -315,7 +315,7 @@ def find_largest_system2(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: return max_atoms, max_nbrs class Dataset: - def __init__(self, atoms, cutoff, bs, n_epochs, buffer_size, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: + def __init__(self, atoms, cutoff, bs, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: if pre_shuffle: shuffle(atoms) self.sample_atoms = atoms[0] @@ -324,8 +324,8 @@ def __init__(self, atoms, cutoff, bs, n_epochs, buffer_size, n_jit_steps= 1, nam finputs.update({k: v for k,v in inputs["ragged"].items()}) self.inputs = finputs - self.n_epochs = n_epochs - self.buffer_size = buffer_size + self.n_epochs = 100 + self.buffer_size = 100 max_atoms, max_nbrs = find_largest_system2(self.inputs, cutoff) self.max_atoms = max_atoms @@ -434,7 +434,7 @@ def init_input(self) -> Dict[str, np.ndarray]: inputs = jax.tree_map(lambda x: jnp.array(x), inputs) return inputs, np.array(box) - def shuffle_and_batch(self): + def shuffle_and_batch(self, sharding=None): """Shuffles and batches the inputs/labels. This function prepares the inputs and labels for the whole training and prefetches the data. @@ -455,10 +455,10 @@ def shuffle_and_batch(self): ) if self.n_jit_steps > 1: ds = ds.batch(batch_size=self.n_jit_steps) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2, sharding) return ds - def batch(self) -> Iterator[jax.Array]: + def batch(self, sharding) -> Iterator[jax.Array]: gen = lambda: self ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) ds = (ds @@ -466,9 +466,9 @@ def batch(self) -> Iterator[jax.Array]: .repeat(self.n_epochs) .batch(batch_size=self.batch_size) ) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2, sharding) return ds - + def cleanup(self): """Removes cache files from disk. Used after training diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 67f67303..a0d26cbf 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -108,7 +108,7 @@ def get_shrink_wrapped_cell(positions): return cell, cell_origin -def prefetch_to_single_device(iterator, size: int): +def prefetch_to_single_device(iterator, size: int, sharding = None): """ inspired by https://flax.readthedocs.io/en/latest/_modules/flax/jax_utils.html#prefetch_to_device @@ -117,7 +117,11 @@ def prefetch_to_single_device(iterator, size: int): queue = collections.deque() def _prefetch(x): - return jnp.asarray(x) + x = jnp.asarray(x) + if sharding: + shape = (2, *([1]*len(x.shape[1:]))) + x = jax.device_put(x, sharding.reshape(shape)) + return x def enqueue(n): for data in itertools.islice(iterator, n): diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 138efbc0..8451a98b 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -50,12 +50,22 @@ def fit( f"n_epochs <= current epoch from checkpoint ({n_epochs} <= {start_epoch})" ) + + from jax.experimental import mesh_utils + from jax.sharding import PositionalSharding + sharding = PositionalSharding(mesh_utils.create_device_mesh((len(jax.devices()),))) + + jax.device_put(state, sharding.replicate()) + train_steps_per_epoch = train_ds.steps_per_epoch() - batch_train_ds = train_ds.shuffle_and_batch() + batch_train_ds = train_ds.shuffle_and_batch(sharding) if val_ds is not None: val_steps_per_epoch = val_ds.steps_per_epoch() - batch_val_ds = val_ds.batch() + batch_val_ds = val_ds.batch(sharding) + + + best_loss = np.inf early_stopping_counter = 0 @@ -74,6 +84,9 @@ def fit( callbacks.on_train_batch_begin(batch=batch_idx) batch = next(batch_train_ds) + + # print(jax.tree_map(lambda x: x.devices(), batch)) + ( (state, train_batch_metrics), batch_loss, From 0c9a931227a9cea20e2cbba35a95508013c84777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 22 Mar 2024 10:29:34 +0100 Subject: [PATCH 110/192] sketch of sharding compatible with njit --- apax/data/preprocessing.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index a0d26cbf..80dc157c 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -116,11 +116,29 @@ def prefetch_to_single_device(iterator, size: int, sharding = None): """ queue = collections.deque() - def _prefetch(x): - x = jnp.asarray(x) + n_devices = 2 + multistep_jit = True + slice_start = 1 + shape = [n_devices] + if multistep_jit: + # replicate over multi-batch axis + # data shape: njit x bs x ... + slice_start = 2 + shape.insert(0, 1) + + def _prefetch(x: jax.Array): + + print(x.shape) + # quit() + shape if sharding: - shape = (2, *([1]*len(x.shape[1:]))) + remaining_axes = [1]*len(x.shape[slice_start:]) + shape = tuple(shape + remaining_axes) x = jax.device_put(x, sharding.reshape(shape)) + print(x.devices()) + quit() + else: + x = jnp.asarray(x) return x def enqueue(n): From 7c32add6235e35c793b733226a774d117553bbd0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 18:06:26 +0000 Subject: [PATCH 111/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/utils/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apax/utils/helpers.py b/apax/utils/helpers.py index e3a0ee64..8f3e5662 100644 --- a/apax/utils/helpers.py +++ b/apax/utils/helpers.py @@ -1,6 +1,7 @@ -import yaml import csv +import yaml + def setup_ase(): """Add uncertainty keys to ASE all properties. From bed5876e17080d1c056ffd10cae88bca4d406a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2024 17:49:53 +0100 Subject: [PATCH 112/192] linting --- apax/utils/jax_md_reduced/simulate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index 71e57a1d..5cd46c1f 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -846,7 +846,12 @@ def U(eps): def sinhx_x(x): """Taylor series for sinh(x) / x as x -> 0.""" return ( - 1 + x**2 / 6 + x**4 / 120 + x**6 / 5040 + x**8 / 362_880 + x**10 / 39_916_800 + 1 + + x**2 / 6 + + x**4 / 120 + + x**6 / 5040 + + x**8 / 362_880 + + x**10 / 39_916_800 ) def exp_iL1(box, R, V, V_b, **kwargs): From eff2fecdd41438038d66fb1bb4ad76d94c5bf8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2024 17:52:05 +0100 Subject: [PATCH 113/192] removed caching from dataset in favor of on the fly NL. removed old data pipeline --- apax/bal/api.py | 14 +- apax/data/initialization.py | 87 ++++--- apax/data/input_pipeline.py | 445 ++++++++---------------------------- apax/data/preprocessing.py | 55 ----- apax/md/ase_calc.py | 11 +- apax/train/eval.py | 9 +- apax/train/run.py | 32 ++- apax/train/trainer.py | 16 +- apax/utils/convert.py | 83 +++---- 9 files changed, 214 insertions(+), 538 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index bc0eea4a..4a50463d 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -8,7 +8,7 @@ from tqdm import trange from apax.bal import feature_maps, kernel, selection, transforms -from apax.data.input_pipeline import AtomisticDataset +from apax.data.input_pipeline import InMemoryDataset from apax.model.builder import ModelBuilder from apax.model.gmnn import EnergyModel from apax.train.checkpoints import ( @@ -16,7 +16,6 @@ check_for_ensemble, restore_parameters, ) -from apax.train.run import initialize_dataset def create_feature_fn( @@ -47,7 +46,7 @@ def create_feature_fn( return feature_fn -def compute_features(feature_fn, dataset: AtomisticDataset): +def compute_features(feature_fn, dataset: InMemoryDataset): """Compute the features of a dataset.""" features = [] n_data = dataset.n_data @@ -86,10 +85,13 @@ def kernel_selection( is_ensemble = n_models > 1 n_train = len(train_atoms) - dataset = initialize_dataset( - config, train_atoms + pool_atoms, read_labels=False, calc_stats=False + dataset = InMemoryDataset( + train_atoms + pool_atoms, + cutoff=config.model.r_max, + bs=processing_batch_size, + n_epochs=1, + ignore_labels=True, ) - dataset.set_batch_size(processing_batch_size) _, init_box = dataset.init_input() diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 68aa59f3..80f89861 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -2,9 +2,6 @@ import numpy as np -from apax.data.input_pipeline import AtomisticDataset, process_inputs -from apax.data.statistics import compute_scale_shift_parameters -from apax.utils.convert import atoms_to_labels from apax.utils.data import load_data, split_atoms, split_idxs log = logging.getLogger(__name__) @@ -38,48 +35,48 @@ def load_data_files(data_config): return train_atoms_list, val_atoms_list -def initialize_dataset( - config, - atoms_list, - read_labels: bool = True, - calc_stats: bool = True, -): - if calc_stats and not read_labels: - raise ValueError( - "Cannot calculate scale/shift parameters without reading labels." - ) - inputs = process_inputs( - atoms_list, - r_max=config.model.r_max, - disable_pbar=config.progress_bar.disable_nl_pbar, - pos_unit=config.data.pos_unit, - ) - labels = atoms_to_labels( - atoms_list, - additional_properties_info=config.data.additional_properties_info, - read_labels=read_labels, - pos_unit=config.data.pos_unit, - energy_unit=config.data.energy_unit, - ) +# def initialize_dataset( +# config, +# atoms_list, +# read_labels: bool = True, +# calc_stats: bool = True, +# ): +# if calc_stats and not read_labels: +# raise ValueError( +# "Cannot calculate scale/shift parameters without reading labels." +# ) +# inputs = process_inputs( +# atoms_list, +# r_max=config.model.r_max, +# disable_pbar=config.progress_bar.disable_nl_pbar, +# pos_unit=config.data.pos_unit, +# ) +# labels = atoms_to_labels( +# atoms_list, +# additional_properties_info=config.data.additional_properties_info, +# read_labels=read_labels, +# pos_unit=config.data.pos_unit, +# energy_unit=config.data.energy_unit, +# ) - if calc_stats: - ds_stats = compute_scale_shift_parameters( - inputs, - labels, - config.data.shift_method, - config.data.scale_method, - config.data.shift_options, - config.data.scale_options, - ) +# if calc_stats: +# ds_stats = compute_scale_shift_parameters( +# inputs, +# labels, +# config.data.shift_method, +# config.data.scale_method, +# config.data.shift_options, +# config.data.scale_options, +# ) - dataset = AtomisticDataset( - inputs, - config.n_epochs, - labels=labels, - buffer_size=config.data.shuffle_buffer_size, - ) +# dataset = InMemoryDataset( +# inputs, +# config.n_epochs, +# labels=labels, +# buffer_size=config.data.shuffle_buffer_size, +# ) - if calc_stats: - return dataset, ds_stats - else: - return dataset +# if calc_stats: +# return dataset, ds_stats +# else: +# return dataset diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 889aad87..8e1f9683 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -1,301 +1,19 @@ import logging -from typing import Dict, Iterator, Optional +from collections import deque +from random import shuffle +from typing import Dict, Iterator import jax import jax.numpy as jnp import numpy as np import tensorflow as tf -from apax.data.preprocessing import dataset_neighborlist, prefetch_to_single_device -from apax.utils.convert import atoms_to_inputs +from apax.data.preprocessing import compute_nl, prefetch_to_single_device +from apax.utils.convert import atoms_to_inputs, atoms_to_labels log = logging.getLogger(__name__) -def find_largest_system(inputs: dict[str, np.ndarray]) -> tuple[int]: - max_atoms = np.max(inputs["fixed"]["n_atoms"]) - nbr_shapes = [idx.shape[1] for idx in inputs["fixed"]["idx"]] # REMOVE - max_nbrs = np.max(nbr_shapes) - return max_atoms, max_nbrs - - -class PadToSpecificSize: - def __init__(self, max_atoms: int, max_nbrs: int) -> None: - """Function is padding all input and label dicts that values are of type ragged - to largest element in the batch. Afterward, the distinction between ragged - and fixed inputs/labels is not needed and all inputs/labels are updated to - one list. - - Parameters - ---------- - max_atoms: Number of atoms that atom-wise inputs will be padded to. - max_nbrs: Number of neighbors that neighborlists will be padded to. - """ - - self.max_atoms = max_atoms - self.max_nbrs = max_nbrs - - def __call__(self, inputs: dict, labels: dict = None) -> tuple[dict, dict]: - """ - Arguments - --------- - - r_inputs : - Inputs of ragged shape. - f_inputs : - Inputs of fixed shape. - r_labels : - Labels of ragged shape. Trainable system properties. - f_labels : - Labels of fixed shape. Trainable system properties. - - Returns - ------- - inputs: - Contains all inputs and all entries are uniformly shaped. - labels: - Contains all labels and all entries are uniformly shaped. - """ - r_inputs = inputs["ragged"] - f_inputs = inputs["fixed"] - for key, val in r_inputs.items(): - if self.max_atoms is None: - r_inputs[key] = val.to_tensor() - # elif key == "idx": - # shape = r_inputs[key].shape - # padded_shape = [shape[0], shape[1], self.max_nbrs] # batch, ij, nbrs - # elif key == "offsets": - # shape = r_inputs[key].shape - # padded_shape = [shape[0], self.max_nbrs, 3] # batch, ij, nbrs # KILL - elif key == "numbers": - shape = r_inputs[key].shape - padded_shape = [shape[0], self.max_atoms] # batch, atoms - else: - shape = r_inputs[key].shape - padded_shape = [shape[0], self.max_atoms, shape[2]] # batch, atoms, 3 - r_inputs[key] = val.to_tensor(shape=padded_shape) - - new_inputs = r_inputs.copy() - new_inputs.update(f_inputs) - - if labels: - r_labels = labels["ragged"] - f_labels = labels["fixed"] - for key, val in r_labels.items(): - if self.max_atoms is None: - r_labels[key] = val.to_tensor() - else: - shape = r_labels[key].shape - padded_shape = [shape[0], self.max_atoms, shape[2]] - r_labels[key] = val.to_tensor(default_value=0.0, shape=padded_shape) - - new_labels = r_labels.copy() - new_labels.update(f_labels) - - return new_inputs, new_labels - else: - return new_inputs - - -def pad_neighborlist(idxs, offsets, max_neighbors): - new_idxs = [] - new_offsets = [] - - for idx, offset in zip(idxs, offsets): - zeros_to_add = max_neighbors - idx.shape[1] - new_idx = np.pad(idx, ((0, 0), (0, zeros_to_add)), "constant").astype(np.int16) - new_offset = np.pad(offset, ((0, zeros_to_add), (0, 0)), "constant").astype(np.int16) - new_idxs.append(new_idx) - new_offsets.append(new_offset) - - return new_idxs, new_offsets - - -def process_inputs( - atoms_list: list, - r_max: float, - disable_pbar=False, - pos_unit: str = "Ang", -) -> dict: - inputs = atoms_to_inputs(atoms_list, pos_unit) # find largest input - idx, offsets, max_neighbors = dataset_neighborlist( - inputs["ragged"]["positions"], - inputs["fixed"]["box"], - r_max=r_max, - disable_pbar=disable_pbar, - ) - - idx, offsets = pad_neighborlist(idx, offsets, max_neighbors) - - inputs["fixed"]["idx"] = idx - inputs["fixed"]["offsets"] = offsets - return inputs - - -def dataset_from_dicts( - inputs: Dict[str, np.ndarray], labels: Optional[Dict[str, np.ndarray]] = None -) -> tf.data.Dataset: - # tf.RaggedTensors should be created from `tf.ragged.stack` - # instead of `tf.ragged.constant` for performance reasons. - # See https://github.com/tensorflow/tensorflow/issues/47853 - for key, val in inputs["ragged"].items(): - inputs["ragged"][key] = tf.ragged.stack(val) - for key, val in inputs["fixed"].items(): - inputs["fixed"][key] = tf.constant(val) - - if labels: - for key, val in labels["ragged"].items(): - labels["ragged"][key] = tf.ragged.stack(val) - for key, val in labels["fixed"].items(): - labels["fixed"][key] = tf.constant(val) - - tensors = (inputs, labels) - else: - tensors = inputs - - ds = tf.data.Dataset.from_tensor_slices(tensors) - - return ds - -from apax.utils.convert import atoms_to_inputs -class AtomisticDataset: - """Class processes inputs/labels and makes them accessible for training.""" - - def __init__( - self, - inputs, - n_epoch: int, - labels=None, - buffer_size: int = 1000, - ) -> None: - """Processes inputs/labels and makes them accessible for training. - - Parameters - ---------- - cutoff : - Radial cutoff in angstrom for the neighbor list. - n_epoch : - Number of epochs - batch_size : - Number of strictures in one batch. - atoms_list : - List of all structures. Entries are ASE atoms objects. - buffer_size : optional - The number of structures that are shuffled for choosing the batches. Should be - significantly larger than the batch size. It is recommended to use the default - value. - """ - self.n_epoch = n_epoch - self.batch_size = None - self.n_jit_steps = 1 - self.buffer_size = buffer_size - - max_atoms, max_nbrs = find_largest_system(inputs) - self.max_atoms = max_atoms - self.max_nbrs = max_nbrs - - self.n_data = len(inputs["fixed"]["n_atoms"]) - - if labels: - self.ds = dataset_from_dicts(inputs, labels) - else: - self.ds = dataset_from_dicts(inputs) - - def set_batch_size(self, batch_size: int): - self.batch_size = self.validate_batch_size(batch_size) - - def batch_multiple_steps(self, n_steps: int): - self.n_jit_steps = n_steps - - def _check_batch_size(self): - if self.batch_size is None: - raise ValueError("Dataset Batch Size has not been set yet") - - def validate_batch_size(self, batch_size: int) -> int: - if batch_size > self.n_data: - msg = ( - f"requested batch size {batch_size} is larger than the number of data" - f" points {self.n_data}. Setting batch size = {self.n_data}" - ) - print("Warning: " + msg) - log.warning(msg) - batch_size = self.n_data - return batch_size - - def steps_per_epoch(self) -> int: - """Returns the number of steps per epoch dependent on the number of data and the - batch size. Steps per epoch are calculated in a way that all epochs have the same - number of steps, and all batches have the same length. To do so, some training - data are dropped in each epoch. - """ - return self.n_data // self.batch_size // self.n_jit_steps - - def init_input(self) -> Dict[str, np.ndarray]: - """Returns first batch of inputs and labels to init the model.""" - inputs = next( - self.ds.batch(1) - .map(PadToSpecificSize(self.max_atoms, self.max_nbrs)) - .take(1) - .as_numpy_iterator() - ) - if isinstance(inputs, tuple): - inputs = inputs[0] # remove labels - - inputs = jax.tree_map(lambda x: jnp.array(x[0]), inputs) - init_box = np.array(inputs["box"]) - inputs = ( - inputs["positions"], - inputs["numbers"], - inputs["idx"], - init_box, - inputs["offsets"], - ) - return inputs, init_box - - def shuffle_and_batch(self) -> Iterator[jax.Array]: - """Shuffles, batches, and pads the inputs/labels. This function prepares the - inputs and labels for the whole training and prefetches the data. - - Returns - ------- - shuffled_ds : - Iterator that returns inputs and labels of one batch in each step. - """ - self._check_batch_size() - #should we shuffle before or after repeat?? - ds = ( - self.ds - .shuffle(buffer_size=self.buffer_size) - .repeat(self.n_epoch) - .batch(batch_size=self.batch_size) - .map(PadToSpecificSize(self.max_atoms, self.max_nbrs)) - ) - - if self.n_jit_steps > 1: - ds = ds.batch(batch_size=self.n_jit_steps) - - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) - return ds - - def batch(self) -> Iterator[jax.Array]: - self._check_batch_size() - ds = self.ds.batch(batch_size=self.batch_size).map( - PadToSpecificSize(self.max_atoms, self.max_nbrs) - ) - - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) - return ds - - - - -import numpy as np -from collections import deque -from random import shuffle -import tensorflow as tf -from apax.data.preprocessing import compute_nl, prefetch_to_single_device -from apax.utils.convert import atoms_to_inputs, atoms_to_labels - def pad_nl(idx, offsets, max_neighbors): zeros_to_add = max_neighbors - idx.shape[1] idx = np.pad(idx, ((0, 0), (0, zeros_to_add)), "constant").astype(np.int16) @@ -303,7 +21,7 @@ def pad_nl(idx, offsets, max_neighbors): return idx, offsets -def find_largest_system2(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: +def find_largest_system(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: max_atoms = np.max(inputs["n_atoms"]) max_nbrs = 0 @@ -314,40 +32,45 @@ def find_largest_system2(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: return max_atoms, max_nbrs -class Dataset: - def __init__(self, atoms, cutoff, bs, n_epochs, buffer_size, n_jit_steps= 1, name="train", pre_shuffle=False) -> None: + +class InMemoryDataset: + def __init__( + self, + atoms, + cutoff, + bs, + n_epochs, + buffer_size=1000, + n_jit_steps=1, + pre_shuffle=False, + ignore_labels=False, + ) -> None: if pre_shuffle: shuffle(atoms) self.sample_atoms = atoms[0] - inputs = atoms_to_inputs(atoms) - finputs = {k: v for k,v in inputs["fixed"].items()} - finputs.update({k: v for k,v in inputs["ragged"].items()}) - self.inputs = finputs + self.inputs = atoms_to_inputs(atoms) self.n_epochs = n_epochs self.buffer_size = buffer_size - max_atoms, max_nbrs = find_largest_system2(self.inputs, cutoff) + max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs - labels = atoms_to_labels(atoms) - flabels = {k: v for k,v in labels["fixed"].items()} - flabels.update({k: v for k,v in labels["ragged"].items()}) - self.labels = flabels + if atoms[0].calc and not ignore_labels: + self.labels = atoms_to_labels(atoms) + else: + self.labels = None self.n_data = len(atoms) - self.count=0 + self.count = 0 self.cutoff = cutoff self.buffer = deque() self.batch_size = self.validate_batch_size(bs) self.n_jit_steps = n_jit_steps - self.name = name - - self.buffer_size = 10 self.enqueue(min(self.buffer_size, self.n_data)) - + def steps_per_epoch(self) -> int: """Returns the number of steps per epoch dependent on the number of data and the batch size. Steps per epoch are calculated in a way that all epochs have the same @@ -355,7 +78,7 @@ def steps_per_epoch(self) -> int: data are dropped in each epoch. """ return self.n_data // self.batch_size // self.n_jit_steps - + def validate_batch_size(self, batch_size: int) -> int: if batch_size > self.n_data: msg = ( @@ -368,20 +91,32 @@ def validate_batch_size(self, batch_size: int) -> int: return batch_size def prepare_item(self, i): - inputs = {k:v[i] for k,v in self.inputs.items()} - labels = {k:v[i] for k,v in self.labels.items()} + inputs = {k: v[i] for k, v in self.inputs.items()} idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] - inputs["positions"] = np.pad(inputs["positions"], ((0, zeros_to_add), (0, 0)), "constant") - inputs["numbers"] = np.pad(inputs["numbers"], (0, zeros_to_add), "constant").astype(np.int16) - inputs["n_atoms"] = np.pad(inputs["n_atoms"], (0, zeros_to_add), "constant").astype(np.int16) + inputs["positions"] = np.pad( + inputs["positions"], ((0, zeros_to_add), (0, 0)), "constant" + ) + inputs["numbers"] = np.pad( + inputs["numbers"], (0, zeros_to_add), "constant" + ).astype(np.int16) + inputs["n_atoms"] = np.pad( + inputs["n_atoms"], (0, zeros_to_add), "constant" + ).astype(np.int16) + + if not self.labels: + return inputs + + labels = {k: v[i] for k, v in self.labels.items()} if "forces" in labels: - labels["forces"] = np.pad(labels["forces"], ((0, zeros_to_add), (0, 0)), "constant") + labels["forces"] = np.pad( + labels["forces"], ((0, zeros_to_add), (0, 0)), "constant" + ) - inputs = {k:tf.constant(v) for k,v in inputs.items()} - labels = {k:tf.constant(v) for k,v in labels.items()} + inputs = {k: tf.constant(v) for k, v in inputs.items()} + labels = {k: tf.constant(v) for k, v in labels.items()} return (inputs, labels) def enqueue(self, num_elements): @@ -389,40 +124,60 @@ def enqueue(self, num_elements): data = self.prepare_item(self.count) self.buffer.append(data) self.count += 1 - + def __iter__(self): - while self.count < self.n_data or len(self.buffer) > 0: + epoch = 0 + while epoch < self.n_epochs or len(self.buffer) > 0: yield self.buffer.popleft() + space = self.buffer_size - len(self.buffer) if self.count + space > self.n_data: space = self.n_data - self.count + + if self.count >= self.n_data and epoch < self.n_epochs: + epoch += 1 + self.count = 0 self.enqueue(space) def make_signature(self) -> tf.TensorSpec: - input_singature = {} - input_singature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") - input_singature["numbers"] = tf.TensorSpec((self.max_atoms,), dtype=tf.int16, name="numbers") - input_singature["positions"] = tf.TensorSpec((self.max_atoms, 3), dtype=tf.float64, name="positions") - input_singature["box"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="box") - input_singature["idx"] = tf.TensorSpec((2, self.max_nbrs), dtype=tf.int16, name="idx") - input_singature["offsets"] = tf.TensorSpec((self.max_nbrs, 3), dtype=tf.float64, name="offsets") + input_signature = {} + input_signature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") + input_signature["numbers"] = tf.TensorSpec( + (self.max_atoms,), dtype=tf.int16, name="numbers" + ) + input_signature["positions"] = tf.TensorSpec( + (self.max_atoms, 3), dtype=tf.float64, name="positions" + ) + input_signature["box"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="box") + input_signature["idx"] = tf.TensorSpec( + (2, self.max_nbrs), dtype=tf.int16, name="idx" + ) + input_signature["offsets"] = tf.TensorSpec( + (self.max_nbrs, 3), dtype=tf.float64, name="offsets" + ) + + if not self.labels: + return input_signature label_signature = {} - label_signature if "energy" in self.labels.keys(): label_signature["energy"] = tf.TensorSpec((), dtype=tf.float64, name="energy") if "forces" in self.labels.keys(): - label_signature["forces"] = tf.TensorSpec((self.max_atoms, 3), dtype=tf.float64, name="forces") + label_signature["forces"] = tf.TensorSpec( + (self.max_atoms, 3), dtype=tf.float64, name="forces" + ) if "stress" in self.labels.keys(): - label_signature["stress"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="stress") - signature = (input_singature, label_signature) + label_signature["stress"] = tf.TensorSpec( + (3, 3), dtype=tf.float64, name="stress" + ) + signature = (input_signature, label_signature) return signature - + def init_input(self) -> Dict[str, np.ndarray]: """Returns first batch of inputs and labels to init the model.""" positions = self.sample_atoms.positions box = self.sample_atoms.cell.array - idx, offsets = compute_nl(positions,box, self.cutoff) + idx, offsets = compute_nl(positions, box, self.cutoff) inputs = ( positions, self.sample_atoms.numbers, @@ -433,7 +188,7 @@ def init_input(self) -> Dict[str, np.ndarray]: inputs = jax.tree_map(lambda x: jnp.array(x), inputs) return inputs, np.array(box) - + def shuffle_and_batch(self): """Shuffles and batches the inputs/labels. This function prepares the inputs and labels for the whole training and prefetches the data. @@ -443,34 +198,22 @@ def shuffle_and_batch(self): ds : Iterator that returns inputs and labels of one batch in each step. """ - gen = lambda: self - ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) - - ds = ( - ds - .cache(self.name) - .repeat(self.n_epochs) - .shuffle(buffer_size=self.buffer_size, reshuffle_each_iteration=True) - .batch(batch_size=self.batch_size) + ds = tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() ) + + ds = ds.shuffle( + buffer_size=self.buffer_size, reshuffle_each_iteration=True + ).batch(batch_size=self.batch_size) if self.n_jit_steps > 1: ds = ds.batch(batch_size=self.n_jit_steps) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) return ds - + def batch(self) -> Iterator[jax.Array]: - gen = lambda: self - ds = tf.data.Dataset.from_generator(gen, output_signature=self.make_signature()) - ds = (ds - .cache(self.name) - .repeat(self.n_epochs) - .batch(batch_size=self.batch_size) + ds = tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() ) + ds = ds.batch(batch_size=self.batch_size) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) return ds - - def cleanup(self): - """Removes cache files from disk. - Used after training - """ - pass \ No newline at end of file diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 67f67303..b52efdbf 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -1,17 +1,11 @@ import collections import itertools import logging -from typing import Callable import jax import jax.numpy as jnp import numpy as np -import tensorflow as tf -from ase import Atoms from matscipy.neighbours import neighbour_list -from tqdm import trange - -from apax.utils.jax_md_reduced import partition, space log = logging.getLogger(__name__) @@ -45,55 +39,6 @@ def compute_nl(position, box, r_max): return neighbor_idxs, offsets - -def dataset_neighborlist( - positions: list[np.array], - boxs: list[np.array], - r_max: float, - disable_pbar: bool = False, -) -> list[int]: - """Calculates the neighbor list of all systems within positions using - a jax_md.partition.NeighborFn. - - Parameters - ---------- - neighbor_fn : - Neighbor list function (jax_md.partition.NeighborFn). - positions : - Cartesian coordinates of all atoms in all structures. - - Returns - ------- - idxs : - Neighbor list of all structures. - """ - log.info("Precomputing neighborlists") - # The JaxMD NL throws an error if np arrays are passed to it in the CPU version - idx_list = [] - offset_list = [] - largest_nl = 0 - - nl_pbar = trange( - len(positions), - desc="Precomputing NL", - ncols=100, - mininterval=0.25, - disable=disable_pbar, - leave=True, - ) - for position, box in zip(positions, boxs): - neighbor_idxs, offsets = compute_nl(position, box, r_max) - n_neighbors = neighbor_idxs.shape[1] - largest_nl = max(largest_nl, n_neighbors) - - offset_list.append(offsets) - idx_list.append(neighbor_idxs) - nl_pbar.update() - nl_pbar.close() - - return idx_list, offset_list, largest_nl - - def get_shrink_wrapped_cell(positions): rmin = np.min(positions, axis=0) rmax = np.max(positions, axis=0) diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 8b01bb3d..73f27658 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -11,7 +11,7 @@ from matscipy.neighbours import neighbour_list from tqdm import trange -from apax.data.initialization import initialize_dataset +from apax.data.input_pipeline import InMemoryDataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters from apax.utils.jax_md_reduced import partition, quantity, space @@ -256,10 +256,13 @@ def batch_eval( """ if self.model is None: self.initialize(atoms_list[0]) - dataset = initialize_dataset( - self.model_config, atoms_list, read_labels=False, calc_stats=False + dataset = InMemoryDataset( + atoms_list, + self.model_config.model.r_max, + batch_size, + n_epochs=1, + ignore_labels=True, ) - dataset.set_batch_size(batch_size) evaluated_atoms_list = [] n_data = dataset.n_data diff --git a/apax/train/eval.py b/apax/train/eval.py index 8a504c2b..b7d69700 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -8,7 +8,7 @@ from tqdm import trange from apax.config import parse_config -from apax.data.initialization import initialize_dataset +from apax.data.input_pipeline import InMemoryDataset from apax.model import ModelBuilder from apax.train.callbacks import initialize_callbacks from apax.train.checkpoints import restore_single_parameters @@ -121,9 +121,10 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): loss_fn = initialize_loss_fn(config.loss) Metrics = initialize_metrics(config.metrics) - raw_ds = load_test_data(config, model_version_path, eval_path, n_test) - - test_ds = initialize_dataset(config, raw_ds, read_labels=False, calc_stats=False) + atoms_list = load_test_data(config, model_version_path, eval_path, n_test) + test_ds = InMemoryDataset( + atoms_list, config.model.r_max, config.data.valid_batch_size + ) _, init_box = test_ds.init_input() diff --git a/apax/train/run.py b/apax/train/run.py index d07011ae..1ac23e0b 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -5,8 +5,8 @@ import jax from apax.config import LossConfig, parse_config -from apax.data.initialization import initialize_dataset, load_data_files -from apax.data.input_pipeline import Dataset +from apax.data.initialization import load_data_files +from apax.data.input_pipeline import InMemoryDataset from apax.data.statistics import compute_scale_shift_parameters from apax.model import ModelBuilder from apax.optimizer import get_opt @@ -68,16 +68,26 @@ def run(user_config, log_level="error"): train_raw_ds, val_raw_ds = load_data_files(config.data) - train_ds = Dataset(train_raw_ds, config.model.r_max, config.data.batch_size, config.n_jitted_steps, name="train", pre_shuffle=True) - val_ds = Dataset(val_raw_ds, config.model.r_max, config.data.valid_batch_size, name="val") + train_ds = InMemoryDataset( + train_raw_ds, + config.model.r_max, + config.data.batch_size, + config.n_epochs, + config.data.shuffle_buffer_size, + config.n_jitted_steps, + pre_shuffle=True, + ) + val_ds = InMemoryDataset( + val_raw_ds, config.model.r_max, config.data.valid_batch_size, config.n_epochs + ) ds_stats = compute_scale_shift_parameters( - train_ds.inputs, - train_ds.labels, - config.data.shift_method, - config.data.scale_method, - config.data.shift_options, - config.data.scale_options, - ) + train_ds.inputs, + train_ds.labels, + config.data.shift_method, + config.data.scale_method, + config.data.shift_options, + config.data.scale_options, + ) # TODO IMPL DELETE FILES log.info("Initializing Model") diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 138efbc0..5f38a3cd 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -10,7 +10,7 @@ from clu import metrics from tqdm import trange -from apax.data.input_pipeline import AtomisticDataset +from apax.data.input_pipeline import InMemoryDataset from apax.train.checkpoints import CheckpointManager, load_state log = logging.getLogger(__name__) @@ -18,14 +18,14 @@ def fit( state, - train_ds: AtomisticDataset, + train_ds: InMemoryDataset, loss_fn, Metrics: metrics.Collection, callbacks: list, n_epochs: int, ckpt_dir, ckpt_interval: int = 1, - val_ds: Optional[AtomisticDataset] = None, + val_ds: Optional[InMemoryDataset] = None, sam_rho=0.0, patience: Optional[int] = None, disable_pbar: bool = False, @@ -107,10 +107,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 1b7aff03..166535ad 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -1,5 +1,3 @@ -from typing import Optional - import jax.numpy as jnp import numpy as np from ase import Atoms @@ -62,14 +60,10 @@ def atoms_to_inputs( Labels are trainable system properties. """ inputs = { - "ragged": { - "positions": [], - "numbers": [], - }, - "fixed": { - "n_atoms": [], - "box": [], - }, + "positions": [], + "numbers": [], + "n_atoms": [], + "box": [], } box = atoms_list[0].cell.array @@ -78,7 +72,7 @@ def atoms_to_inputs( for atoms in atoms_list: box = (atoms.cell.array * unit_dict[pos_unit]).astype(DTYPE) box = box.T # takes row and column convention of ase into account - inputs["fixed"]["box"].append(box) + inputs["box"].append(box) if pbc != np.all(box > 1e-6): raise ValueError( @@ -86,31 +80,24 @@ def atoms_to_inputs( ) if np.all(box < 1e-6): - inputs["ragged"]["positions"].append( + inputs["positions"].append( (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) ) else: inv_box = np.linalg.inv(box) - inputs["ragged"]["positions"].append( - np.array( - space.transform( - inv_box, (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) - ) - ) - ) + pos = (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) + frac_pos = space.transform(inv_box, pos) + inputs["positions"].append(np.array(frac_pos)) - inputs["ragged"]["numbers"].append(atoms.numbers) - inputs["fixed"]["n_atoms"].append(len(atoms)) + inputs["numbers"].append(atoms.numbers) + inputs["n_atoms"].append(len(atoms)) - inputs["fixed"] = prune_dict(inputs["fixed"]) - inputs["ragged"] = prune_dict(inputs["ragged"]) + inputs = prune_dict(inputs) return inputs def atoms_to_labels( atoms_list: list[Atoms], - additional_properties_info: Optional[dict] = {}, - read_labels: bool = True, pos_unit: str = "Ang", energy_unit: str = "eV", ) -> dict[str, dict[str, list]]: @@ -127,43 +114,29 @@ def atoms_to_labels( labels : Labels are trainable system properties. """ - if not read_labels: - return None labels = { - "ragged": { - "forces": [], - }, - "fixed": { - "energy": [], - "stress": [], - }, + "forces": [], + "energy": [], + "stress": [], } - for key in additional_properties_info.keys(): - shape = additional_properties_info[key] - placeholder = {key: []} - labels[shape].update(placeholder) + # for key in atoms_list[0].calc.results.keys(): + # if key not in labels.keys(): + # placeholder = {key: []} + # labels.update(placeholder) for atoms in atoms_list: for key, val in atoms.calc.results.items(): if key == "forces": - labels["ragged"][key].append( - val * unit_dict[energy_unit] / unit_dict[pos_unit] - ) + labels[key].append(val * unit_dict[energy_unit] / unit_dict[pos_unit]) elif key == "energy": - labels["fixed"][key].append(val * unit_dict[energy_unit]) + labels[key].append(val * unit_dict[energy_unit]) elif key == "stress": - stress = ( - atoms.get_stress(voigt=False) - * unit_dict[energy_unit] - / (unit_dict[pos_unit] ** 3) - ) - labels["fixed"][key].append(stress * atoms.cell.volume) - - elif key in additional_properties_info.keys(): - shape = additional_properties_info[key] - labels[shape][key].append(atoms.calc.results[key]) - - labels["fixed"] = prune_dict(labels["fixed"]) - labels["ragged"] = prune_dict(labels["ragged"]) + factor = unit_dict[energy_unit] / (unit_dict[pos_unit] ** 3) + stress = atoms.get_stress(voigt=False) * factor + labels[key].append(stress * atoms.cell.volume) + # else: + # labels[key].append(atoms.calc.results[key]) + + labels = prune_dict(labels) return labels From 960b02876e06ab229d44db2e3fa2ddf9a77370eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2024 17:52:48 +0100 Subject: [PATCH 114/192] updated tests with new data pipeline --- tests/unit_tests/data/test_input_pipeline.py | 240 ++++++++----------- tests/unit_tests/data/test_statistics.py | 6 +- 2 files changed, 98 insertions(+), 148 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 7ab1728b..124c0da0 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -5,129 +5,87 @@ from ase.calculators.singlepoint import SinglePointCalculator from jax import vmap -from apax.data.input_pipeline import AtomisticDataset, PadToSpecificSize, process_inputs +from apax.data.input_pipeline import InMemoryDataset +from apax.data.preprocessing import compute_nl from apax.model.gmnn import disp_fn -from apax.utils.convert import atoms_to_labels +from apax.utils.convert import atoms_to_inputs, atoms_to_labels from apax.utils.data import split_atoms, split_idxs from apax.utils.random import seed_py_np_tf - -@pytest.mark.parametrize( - "num_data, pbc, calc_results, external_labels", - ( - [5, False, ["energy"], None], - [5, False, ["energy", "forces"], None], - [5, True, ["energy", "forces"], None], - [ - 5, - True, - ["energy", "forces"], - [{ - "name": "ma_tensors", - "shape": "fixed", - "values": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)), - }], - ], - ), -) -def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): - batch_size = 2 - r_max = 6.0 - - if external_labels: - label_info = {} - for label in external_labels: - label_info[label["name"]] = label["shape"] - - for a, v in zip(example_atoms, label["values"]): - a.calc.results[label["name"]] = v - else: - label_info = {} - - inputs = process_inputs( - example_atoms, - r_max=r_max, - disable_pbar=True, - ) - labels = atoms_to_labels(example_atoms, additional_properties_info=label_info) - - ds = AtomisticDataset( - inputs, - 1, - labels=labels, - buffer_size=1000, - ) - ds.set_batch_size(batch_size) - assert ds.steps_per_epoch() == num_data // batch_size - - ds = ds.shuffle_and_batch() - - sample_inputs, sample_labels = next(ds) - - assert "box" in sample_inputs - assert len(sample_inputs["box"]) == batch_size - assert len(sample_inputs["box"][0]) == 3 - - assert "numbers" in sample_inputs - for i in range(batch_size): - assert len(sample_inputs["numbers"][i]) == max(sample_inputs["n_atoms"]) - - assert "idx" in sample_inputs - assert len(sample_inputs["idx"][0]) == len(sample_inputs["idx"][1]) - - assert "positions" in sample_inputs - assert len(sample_inputs["positions"][0][0]) == 3 - for i in range(batch_size): - assert len(sample_inputs["positions"][i]) == max(sample_inputs["n_atoms"]) - - assert "n_atoms" in sample_inputs - assert len(sample_inputs["n_atoms"]) == batch_size - - assert "energy" in sample_labels - assert len(sample_labels["energy"]) == batch_size - - if "forces" in calc_results: - assert "forces" in sample_labels - assert len(sample_labels["forces"][0][0]) == 3 - for i in range(batch_size): - assert len(sample_labels["forces"][i]) == max(sample_inputs["n_atoms"]) - - if external_labels: - assert "ma_tensors" in sample_labels - assert len(sample_labels["ma_tensors"]) == batch_size - - sample_inputs2, _ = next(ds) - assert (sample_inputs["positions"][0][0] != sample_inputs2["positions"][0][0]).all() - - -def test_pad_to_specific_size(): - idx_1 = [[1, 4, 3], [3, 1, 4]] - idx_2 = [[5, 4, 2, 3, 1], [1, 2, 3, 4, 5]] - r_inp = {"idx": tf.ragged.constant([idx_1, idx_2])} - p_inp = {"n_atoms": tf.constant([3, 5])} - f_1 = [[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]] - f_2 = [[3.0, 3.0, 3.0], [3.0, 3.0, 3.0], [3.0, 3.0, 3.0]] - r_lab = {"forces": tf.ragged.constant([f_1, f_2])} - p_lab = {"energy": tf.constant([103.3, 98.4])} - inputs = {"fixed": p_inp, "ragged": r_inp} - labels = {"fixed": p_lab, "ragged": r_lab} - - max_atoms = 5 - max_nbrs = 6 - - padding_fn = PadToSpecificSize(max_atoms=max_atoms, max_nbrs=max_nbrs) - - inputs, labels = padding_fn(inputs, labels) - - assert "idx" in inputs - assert inputs["idx"].shape == [2, 2, 6] - - assert "n_atoms" in inputs - - assert "forces" in labels - assert labels["forces"].shape == [2, 5, 3] - - assert "energy" in labels +# TODO REENABLE LATER +# @pytest.mark.parametrize( +# "num_data, pbc, calc_results, external_labels", +# ( +# [5, False, ["energy"], None], +# [5, False, ["energy", "forces"], None], +# [5, True, ["energy", "forces"], None], +# [ +# 5, +# True, +# ["energy", "forces"], +# [{ +# "name": "ma_tensors", +# "values": np.random.uniform(low=-1.0, high=1.0, size=(5, 3, 3)), +# }], +# ], +# ), +# ) +# def test_input_pipeline(example_atoms, calc_results, num_data, external_labels): +# batch_size = 2 +# r_max = 6.0 + +# if external_labels: +# for label in external_labels: +# for a, v in zip(example_atoms, label["values"]): +# a.calc.results[label["name"]] = v + +# ds = InMemoryDataset( +# example_atoms, +# r_max, +# batch_size, +# 1, +# buffer_size=1000, +# ) +# assert ds.steps_per_epoch() == num_data // batch_size + +# ds = ds.shuffle_and_batch() + +# sample_inputs, sample_labels = next(ds) + +# assert "box" in sample_inputs +# assert len(sample_inputs["box"]) == batch_size +# assert len(sample_inputs["box"][0]) == 3 + +# assert "numbers" in sample_inputs +# for i in range(batch_size): +# assert len(sample_inputs["numbers"][i]) == max(sample_inputs["n_atoms"]) + +# assert "idx" in sample_inputs +# assert len(sample_inputs["idx"][0]) == len(sample_inputs["idx"][1]) + +# assert "positions" in sample_inputs +# assert len(sample_inputs["positions"][0][0]) == 3 +# for i in range(batch_size): +# assert len(sample_inputs["positions"][i]) == max(sample_inputs["n_atoms"]) + +# assert "n_atoms" in sample_inputs +# assert len(sample_inputs["n_atoms"]) == batch_size + +# assert "energy" in sample_labels +# assert len(sample_labels["energy"]) == batch_size + +# if "forces" in calc_results: +# assert "forces" in sample_labels +# assert len(sample_labels["forces"][0][0]) == 3 +# for i in range(batch_size): +# assert len(sample_labels["forces"][i]) == max(sample_inputs["n_atoms"]) + +# if external_labels: +# assert "ma_tensors" in sample_labels +# assert len(sample_labels["ma_tensors"]) == batch_size + +# sample_inputs2, _ = next(ds) +# assert (sample_inputs["positions"][0][0] != sample_inputs2["positions"][0][0]).all() @pytest.mark.parametrize( @@ -165,32 +123,28 @@ def test_split_data(example_atoms): ), ) def test_convert_atoms_to_arrays(example_atoms, pbc): - inputs = process_inputs(example_atoms, r_max=6.0) - labels = atoms_to_labels(example_atoms, read_labels=True) - - assert "fixed" in inputs - assert "ragged" in inputs - assert "fixed" or "ragged" in labels + inputs = atoms_to_inputs(example_atoms) + labels = atoms_to_labels(example_atoms) - assert "positions" in inputs["ragged"] - assert len(inputs["ragged"]["positions"]) == len(example_atoms) + assert "positions" in inputs + assert len(inputs["positions"]) == len(example_atoms) - assert "numbers" in inputs["ragged"] - assert len(inputs["ragged"]["numbers"]) == len(example_atoms) + assert "numbers" in inputs + assert len(inputs["numbers"]) == len(example_atoms) - assert "box" in inputs["fixed"] - assert len(inputs["fixed"]["box"]) == len(example_atoms) + assert "box" in inputs + assert len(inputs["box"]) == len(example_atoms) if not pbc: - assert np.all(inputs["fixed"]["box"][0] < 1e-6) + assert np.all(inputs["box"][0] < 1e-6) - assert "n_atoms" in inputs["fixed"] - assert len(inputs["fixed"]["n_atoms"]) == len(example_atoms) + assert "n_atoms" in inputs + assert len(inputs["n_atoms"]) == len(example_atoms) - assert "energy" in labels["fixed"] - assert len(labels["fixed"]["energy"]) == len(example_atoms) + assert "energy" in labels + assert len(labels["energy"]) == len(example_atoms) - assert "forces" in labels["ragged"] - assert len(labels["ragged"]["forces"]) == len(example_atoms) + assert "forces" in labels + assert len(labels["forces"]) == len(example_atoms) @pytest.mark.parametrize( @@ -234,18 +188,16 @@ def test_neighbors_and_displacements(pbc, calc_results, cell): results[key] = result_shapes[key] atoms.calc = SinglePointCalculator(atoms, **results) - inputs = process_inputs([atoms], r_max=r_max, disable_pbar=True) - - idx = np.asarray(inputs["ragged"]["idx"])[0] - offsets = np.asarray(inputs["ragged"]["offsets"][0]) - box = np.asarray(inputs["fixed"]["box"][0]) + inputs = atoms_to_inputs([atoms]) + box = np.asarray(inputs["box"][0]) + idx, offsets = compute_nl(inputs["positions"][0], box, r_max) Ri = positions[idx[0]] Rj = positions[idx[1]] + offsets matscipy_dr_vec = Rj - Ri matscipy_dr_vec = np.asarray(matscipy_dr_vec) - positions = np.asarray(inputs["ragged"]["positions"][0]) + positions = np.asarray(inputs["positions"][0]) Ri = positions[idx[0]] Rj = positions[idx[1]] displacement = vmap(disp_fn, (0, 0, None, None), 0) diff --git a/tests/unit_tests/data/test_statistics.py b/tests/unit_tests/data/test_statistics.py index 6ae80c90..db5a1742 100644 --- a/tests/unit_tests/data/test_statistics.py +++ b/tests/unit_tests/data/test_statistics.py @@ -2,9 +2,8 @@ from ase import Atoms from ase.calculators.singlepoint import SinglePointCalculator -from apax.data.input_pipeline import process_inputs from apax.data.statistics import PerElementRegressionShift -from apax.utils.convert import atoms_to_labels +from apax.utils.convert import atoms_to_inputs, atoms_to_labels def test_energy_per_element(): @@ -24,9 +23,8 @@ def test_energy_per_element(): energies.append(energy) atoms.calc = SinglePointCalculator(atoms, energy=energy) - inputs = process_inputs( + inputs = atoms_to_inputs( atoms_list, - r_max=6.5, ) labels = atoms_to_labels(atoms_list) From 6579eb833a5e510ca2eb49aa53106e245adce24f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:00:00 +0000 Subject: [PATCH 115/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 5f38a3cd..f0e99ef5 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,12 +107,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 6a3ce5bc6a85a57b7cb0ac88dfbf0df1f178f4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2024 18:06:07 +0100 Subject: [PATCH 116/192] linting --- tests/unit_tests/data/test_input_pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 124c0da0..8d9209a5 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -1,11 +1,9 @@ import numpy as np import pytest -import tensorflow as tf from ase import Atoms from ase.calculators.singlepoint import SinglePointCalculator from jax import vmap -from apax.data.input_pipeline import InMemoryDataset from apax.data.preprocessing import compute_nl from apax.model.gmnn import disp_fn from apax.utils.convert import atoms_to_inputs, atoms_to_labels From 9c235f07964b15a833ce6f1429ceacdbb082e56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 26 Mar 2024 11:26:46 +0100 Subject: [PATCH 117/192] removed commented out code --- apax/data/initialization.py | 47 ------------------------------------- apax/train/run.py | 1 - 2 files changed, 48 deletions(-) diff --git a/apax/data/initialization.py b/apax/data/initialization.py index 80f89861..d81d73e2 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -33,50 +33,3 @@ def load_data_files(data_config): raise ValueError("input data path/paths not defined") return train_atoms_list, val_atoms_list - - -# def initialize_dataset( -# config, -# atoms_list, -# read_labels: bool = True, -# calc_stats: bool = True, -# ): -# if calc_stats and not read_labels: -# raise ValueError( -# "Cannot calculate scale/shift parameters without reading labels." -# ) -# inputs = process_inputs( -# atoms_list, -# r_max=config.model.r_max, -# disable_pbar=config.progress_bar.disable_nl_pbar, -# pos_unit=config.data.pos_unit, -# ) -# labels = atoms_to_labels( -# atoms_list, -# additional_properties_info=config.data.additional_properties_info, -# read_labels=read_labels, -# pos_unit=config.data.pos_unit, -# energy_unit=config.data.energy_unit, -# ) - -# if calc_stats: -# ds_stats = compute_scale_shift_parameters( -# inputs, -# labels, -# config.data.shift_method, -# config.data.scale_method, -# config.data.shift_options, -# config.data.scale_options, -# ) - -# dataset = InMemoryDataset( -# inputs, -# config.n_epochs, -# labels=labels, -# buffer_size=config.data.shuffle_buffer_size, -# ) - -# if calc_stats: -# return dataset, ds_stats -# else: -# return dataset diff --git a/apax/train/run.py b/apax/train/run.py index 1ac23e0b..f1dbeb39 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -88,7 +88,6 @@ def run(user_config, log_level="error"): config.data.shift_options, config.data.scale_options, ) - # TODO IMPL DELETE FILES log.info("Initializing Model") sample_input, init_box = train_ds.init_input() From 5811501bfbfbd2beda385cee0acef4d0ff45d043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 26 Mar 2024 11:27:04 +0100 Subject: [PATCH 118/192] renamed prepare item to prepare data --- apax/data/input_pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 8e1f9683..d6547cfb 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -90,7 +90,7 @@ def validate_batch_size(self, batch_size: int) -> int: batch_size = self.n_data return batch_size - def prepare_item(self, i): + def prepare_data(self, i): inputs = {k: v[i] for k, v in self.inputs.items()} idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) @@ -121,7 +121,7 @@ def prepare_item(self, i): def enqueue(self, num_elements): for _ in range(num_elements): - data = self.prepare_item(self.count) + data = self.prepare_data(self.count) self.buffer.append(data) self.count += 1 From 4dd0082d9734ef921179a6dddc49f64abd23ce9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 27 Mar 2024 10:24:49 +0100 Subject: [PATCH 119/192] switched to cached dataset --- apax/data/input_pipeline.py | 201 ++++++++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 9 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index d6547cfb..260d70a0 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -2,6 +2,7 @@ from collections import deque from random import shuffle from typing import Dict, Iterator +import uuid import jax import jax.numpy as jnp @@ -33,6 +34,192 @@ def find_largest_system(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: return max_atoms, max_nbrs +# class InMemoryDataset: +# def __init__( +# self, +# atoms, +# cutoff, +# bs, +# n_epochs, +# buffer_size=1000, +# n_jit_steps=1, +# pre_shuffle=False, +# ignore_labels=False, +# ) -> None: +# if pre_shuffle: +# shuffle(atoms) +# self.sample_atoms = atoms[0] +# self.inputs = atoms_to_inputs(atoms) + +# self.n_epochs = n_epochs +# self.buffer_size = buffer_size + +# max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) +# self.max_atoms = max_atoms +# self.max_nbrs = max_nbrs + +# if atoms[0].calc and not ignore_labels: +# self.labels = atoms_to_labels(atoms) +# else: +# self.labels = None + +# self.n_data = len(atoms) +# self.count = 0 +# self.cutoff = cutoff +# self.buffer = deque() +# self.batch_size = self.validate_batch_size(bs) +# self.n_jit_steps = n_jit_steps + +# self.enqueue(min(self.buffer_size, self.n_data)) + +# def steps_per_epoch(self) -> int: +# """Returns the number of steps per epoch dependent on the number of data and the +# batch size. Steps per epoch are calculated in a way that all epochs have the same +# number of steps, and all batches have the same length. To do so, some training +# data are dropped in each epoch. +# """ +# return self.n_data // self.batch_size // self.n_jit_steps + +# def validate_batch_size(self, batch_size: int) -> int: +# if batch_size > self.n_data: +# msg = ( +# f"requested batch size {batch_size} is larger than the number of data" +# f" points {self.n_data}. Setting batch size = {self.n_data}" +# ) +# print("Warning: " + msg) +# log.warning(msg) +# batch_size = self.n_data +# return batch_size + +# def prepare_data(self, i): +# inputs = {k: v[i] for k, v in self.inputs.items()} +# idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) +# inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) + +# zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] +# inputs["positions"] = np.pad( +# inputs["positions"], ((0, zeros_to_add), (0, 0)), "constant" +# ) +# inputs["numbers"] = np.pad( +# inputs["numbers"], (0, zeros_to_add), "constant" +# ).astype(np.int16) +# inputs["n_atoms"] = np.pad( +# inputs["n_atoms"], (0, zeros_to_add), "constant" +# ).astype(np.int16) + +# if not self.labels: +# return inputs + +# labels = {k: v[i] for k, v in self.labels.items()} +# if "forces" in labels: +# labels["forces"] = np.pad( +# labels["forces"], ((0, zeros_to_add), (0, 0)), "constant" +# ) + +# inputs = {k: tf.constant(v) for k, v in inputs.items()} +# labels = {k: tf.constant(v) for k, v in labels.items()} +# return (inputs, labels) + +# def enqueue(self, num_elements): +# for _ in range(num_elements): +# data = self.prepare_data(self.count) +# self.buffer.append(data) +# self.count += 1 + +# def __iter__(self): +# epoch = 0 +# while epoch < self.n_epochs or len(self.buffer) > 0: +# yield self.buffer.popleft() + +# space = self.buffer_size - len(self.buffer) +# if self.count + space > self.n_data: +# space = self.n_data - self.count + +# if self.count >= self.n_data and epoch < self.n_epochs: +# epoch += 1 +# self.count = 0 +# self.enqueue(space) + +# def make_signature(self) -> tf.TensorSpec: +# input_signature = {} +# input_signature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") +# input_signature["numbers"] = tf.TensorSpec( +# (self.max_atoms,), dtype=tf.int16, name="numbers" +# ) +# input_signature["positions"] = tf.TensorSpec( +# (self.max_atoms, 3), dtype=tf.float64, name="positions" +# ) +# input_signature["box"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="box") +# input_signature["idx"] = tf.TensorSpec( +# (2, self.max_nbrs), dtype=tf.int16, name="idx" +# ) +# input_signature["offsets"] = tf.TensorSpec( +# (self.max_nbrs, 3), dtype=tf.float64, name="offsets" +# ) + +# if not self.labels: +# return input_signature + +# label_signature = {} +# if "energy" in self.labels.keys(): +# label_signature["energy"] = tf.TensorSpec((), dtype=tf.float64, name="energy") +# if "forces" in self.labels.keys(): +# label_signature["forces"] = tf.TensorSpec( +# (self.max_atoms, 3), dtype=tf.float64, name="forces" +# ) +# if "stress" in self.labels.keys(): +# label_signature["stress"] = tf.TensorSpec( +# (3, 3), dtype=tf.float64, name="stress" +# ) +# signature = (input_signature, label_signature) +# return signature + +# def init_input(self) -> Dict[str, np.ndarray]: +# """Returns first batch of inputs and labels to init the model.""" +# positions = self.sample_atoms.positions +# box = self.sample_atoms.cell.array +# idx, offsets = compute_nl(positions, box, self.cutoff) +# inputs = ( +# positions, +# self.sample_atoms.numbers, +# idx, +# box, +# offsets, +# ) + +# inputs = jax.tree_map(lambda x: jnp.array(x), inputs) +# return inputs, np.array(box) + +# def shuffle_and_batch(self): +# """Shuffles and batches the inputs/labels. This function prepares the +# inputs and labels for the whole training and prefetches the data. + +# Returns +# ------- +# ds : +# Iterator that returns inputs and labels of one batch in each step. +# """ +# ds = tf.data.Dataset.from_generator( +# lambda: self, output_signature=self.make_signature() +# ) + +# ds = ds.shuffle( +# buffer_size=self.buffer_size, reshuffle_each_iteration=True +# ).batch(batch_size=self.batch_size) +# if self.n_jit_steps > 1: +# ds = ds.batch(batch_size=self.n_jit_steps) +# ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) +# return ds + +# def batch(self) -> Iterator[jax.Array]: +# ds = tf.data.Dataset.from_generator( +# lambda: self, output_signature=self.make_signature() +# ) +# ds = ds.batch(batch_size=self.batch_size) +# ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) +# return ds + + class InMemoryDataset: def __init__( self, @@ -68,6 +255,7 @@ def __init__( self.buffer = deque() self.batch_size = self.validate_batch_size(bs) self.n_jit_steps = n_jit_steps + self.name = str(uuid.uuid4()) self.enqueue(min(self.buffer_size, self.n_data)) @@ -126,17 +314,12 @@ def enqueue(self, num_elements): self.count += 1 def __iter__(self): - epoch = 0 - while epoch < self.n_epochs or len(self.buffer) > 0: + while self.count < self.n_data or len(self.buffer) > 0: yield self.buffer.popleft() space = self.buffer_size - len(self.buffer) if self.count + space > self.n_data: space = self.n_data - self.count - - if self.count >= self.n_data and epoch < self.n_epochs: - epoch += 1 - self.count = 0 self.enqueue(space) def make_signature(self) -> tf.TensorSpec: @@ -200,7 +383,7 @@ def shuffle_and_batch(self): """ ds = tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() - ) + ).cache(self.name).repeat(self.n_epochs) ds = ds.shuffle( buffer_size=self.buffer_size, reshuffle_each_iteration=True @@ -213,7 +396,7 @@ def shuffle_and_batch(self): def batch(self) -> Iterator[jax.Array]: ds = tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() - ) + ).cache(self.name).repeat(self.n_epochs) ds = ds.batch(batch_size=self.batch_size) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) - return ds + return ds \ No newline at end of file From 83a0d3436516e2424b5df014a45012299a04c8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 27 Mar 2024 18:37:24 +0100 Subject: [PATCH 120/192] implemented automatic handling of cache files. --- apax/data/input_pipeline.py | 18 ++++++++++++++---- apax/train/run.py | 3 ++- apax/train/trainer.py | 5 +++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 260d70a0..1d93dc5e 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -3,6 +3,7 @@ from random import shuffle from typing import Dict, Iterator import uuid +from pathlib import Path import jax import jax.numpy as jnp @@ -231,6 +232,7 @@ def __init__( n_jit_steps=1, pre_shuffle=False, ignore_labels=False, + cache_path = "." ) -> None: if pre_shuffle: shuffle(atoms) @@ -255,7 +257,7 @@ def __init__( self.buffer = deque() self.batch_size = self.validate_batch_size(bs) self.n_jit_steps = n_jit_steps - self.name = str(uuid.uuid4()) + self.file = Path(cache_path) / str(uuid.uuid4()) self.enqueue(min(self.buffer_size, self.n_data)) @@ -383,7 +385,7 @@ def shuffle_and_batch(self): """ ds = tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() - ).cache(self.name).repeat(self.n_epochs) + ).cache(self.file.as_posix()).repeat(self.n_epochs) ds = ds.shuffle( buffer_size=self.buffer_size, reshuffle_each_iteration=True @@ -396,7 +398,15 @@ def shuffle_and_batch(self): def batch(self) -> Iterator[jax.Array]: ds = tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() - ).cache(self.name).repeat(self.n_epochs) + ).cache(self.file.as_posix()).repeat(self.n_epochs) ds = ds.batch(batch_size=self.batch_size) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) - return ds \ No newline at end of file + return ds + + def cleanup(self): + for p in self.file.parent.glob(f"{self.file.name}.data*"): + p.unlink() + + index_file = self.file.parent / f"{self.file.name}.index" + index_file.unlink() + \ No newline at end of file diff --git a/apax/train/run.py b/apax/train/run.py index f1dbeb39..6606348e 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -76,9 +76,10 @@ def run(user_config, log_level="error"): config.data.shuffle_buffer_size, config.n_jitted_steps, pre_shuffle=True, + cache_path=config.data.model_version_path, ) val_ds = InMemoryDataset( - val_raw_ds, config.model.r_max, config.data.valid_batch_size, config.n_epochs + val_raw_ds, config.model.r_max, config.data.valid_batch_size, config.n_epochs, cache_path=config.data.model_version_path, ) ds_stats = compute_scale_shift_parameters( train_ds.inputs, diff --git a/apax/train/trainer.py b/apax/train/trainer.py index f0e99ef5..7575d23e 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -1,5 +1,6 @@ import functools import logging +from pathlib import Path import time from functools import partial from typing import Callable, Optional @@ -142,6 +143,10 @@ def fit( epoch_pbar.close() callbacks.on_train_end() + train_ds.cleanup() + if val_ds: + val_ds.cleanup() + def global_norm(updates) -> jnp.ndarray: """Returns the l2 norm of the input. From ab55328361f0645e28210d755e1393aeee3d4ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 27 Mar 2024 19:35:20 +0100 Subject: [PATCH 121/192] moved dataset initialization to separate function --- apax/train/run.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/apax/train/run.py b/apax/train/run.py index 6606348e..0dee0f08 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -50,22 +50,7 @@ def initialize_loss_fn(loss_config_list: List[LossConfig]) -> LossCollection: loss_funcs.append(Loss(**loss.model_dump())) return LossCollection(loss_funcs) - -def run(user_config, log_level="error"): - config = parse_config(user_config) - - seed_py_np_tf(config.seed) - rng_key = jax.random.PRNGKey(config.seed) - - log.info("Initializing directories") - config.data.model_version_path.mkdir(parents=True, exist_ok=True) - setup_logging(config.data.model_version_path / "train.log", log_level) - config.dump_config(config.data.model_version_path) - - callbacks = initialize_callbacks(config.callbacks, config.data.model_version_path) - loss_fn = initialize_loss_fn(config.loss) - Metrics = initialize_metrics(config.metrics) - +def initialize_datasets(config): train_raw_ds, val_raw_ds = load_data_files(config.data) train_ds = InMemoryDataset( @@ -89,6 +74,26 @@ def run(user_config, log_level="error"): config.data.shift_options, config.data.scale_options, ) + return train_ds, val_ds, ds_stats + + + +def run(user_config, log_level="error"): + config = parse_config(user_config) + + seed_py_np_tf(config.seed) + rng_key = jax.random.PRNGKey(config.seed) + + log.info("Initializing directories") + config.data.model_version_path.mkdir(parents=True, exist_ok=True) + setup_logging(config.data.model_version_path / "train.log", log_level) + config.dump_config(config.data.model_version_path) + + callbacks = initialize_callbacks(config.callbacks, config.data.model_version_path) + loss_fn = initialize_loss_fn(config.loss) + Metrics = initialize_metrics(config.metrics) + + train_ds, val_ds, ds_stats = initialize_datasets(config) log.info("Initializing Model") sample_input, init_box = train_ds.init_input() From ec3b2cb47d4503963c7f3c8dfa325f8c92bacef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 29 Mar 2024 12:55:14 +0100 Subject: [PATCH 122/192] convert atomic numbers to int16 --- apax/utils/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 166535ad..b6bfd76e 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -89,7 +89,7 @@ def atoms_to_inputs( frac_pos = space.transform(inv_box, pos) inputs["positions"].append(np.array(frac_pos)) - inputs["numbers"].append(atoms.numbers) + inputs["numbers"].append(atoms.numbers.astype(np.int16)) inputs["n_atoms"].append(len(atoms)) inputs = prune_dict(inputs) From 79a9e69e703bf72b3a279907df444f94db11a98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 29 Mar 2024 12:57:54 +0100 Subject: [PATCH 123/192] implemented OTFInMemoryDataset. Usage for single epoch tasks --- apax/bal/api.py | 6 +- apax/config/train_config.py | 1 + apax/data/input_pipeline.py | 278 +++++++++++------------------------- apax/md/ase_calc.py | 4 +- apax/train/eval.py | 4 +- apax/train/run.py | 12 +- 6 files changed, 95 insertions(+), 210 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index 4a50463d..f891c5c9 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -8,7 +8,7 @@ from tqdm import trange from apax.bal import feature_maps, kernel, selection, transforms -from apax.data.input_pipeline import InMemoryDataset +from apax.data.input_pipeline import OTFInMemoryDataset from apax.model.builder import ModelBuilder from apax.model.gmnn import EnergyModel from apax.train.checkpoints import ( @@ -46,7 +46,7 @@ def create_feature_fn( return feature_fn -def compute_features(feature_fn, dataset: InMemoryDataset): +def compute_features(feature_fn, dataset: OTFInMemoryDataset): """Compute the features of a dataset.""" features = [] n_data = dataset.n_data @@ -85,7 +85,7 @@ def kernel_selection( is_ensemble = n_models > 1 n_train = len(train_atoms) - dataset = InMemoryDataset( + dataset = OTFInMemoryDataset( train_atoms + pool_atoms, cutoff=config.model.r_max, bs=processing_batch_size, diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 350849d0..5733dec8 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -50,6 +50,7 @@ class DataConfig(BaseModel, extra="forbid"): directory: str experiment: str + ds_type: Literal["cached", "otf"] = "cached" data_path: Optional[str] = None train_data_path: Optional[str] = None val_data_path: Optional[str] = None diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 1d93dc5e..1a014c55 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -35,192 +35,6 @@ def find_largest_system(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: return max_atoms, max_nbrs -# class InMemoryDataset: -# def __init__( -# self, -# atoms, -# cutoff, -# bs, -# n_epochs, -# buffer_size=1000, -# n_jit_steps=1, -# pre_shuffle=False, -# ignore_labels=False, -# ) -> None: -# if pre_shuffle: -# shuffle(atoms) -# self.sample_atoms = atoms[0] -# self.inputs = atoms_to_inputs(atoms) - -# self.n_epochs = n_epochs -# self.buffer_size = buffer_size - -# max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) -# self.max_atoms = max_atoms -# self.max_nbrs = max_nbrs - -# if atoms[0].calc and not ignore_labels: -# self.labels = atoms_to_labels(atoms) -# else: -# self.labels = None - -# self.n_data = len(atoms) -# self.count = 0 -# self.cutoff = cutoff -# self.buffer = deque() -# self.batch_size = self.validate_batch_size(bs) -# self.n_jit_steps = n_jit_steps - -# self.enqueue(min(self.buffer_size, self.n_data)) - -# def steps_per_epoch(self) -> int: -# """Returns the number of steps per epoch dependent on the number of data and the -# batch size. Steps per epoch are calculated in a way that all epochs have the same -# number of steps, and all batches have the same length. To do so, some training -# data are dropped in each epoch. -# """ -# return self.n_data // self.batch_size // self.n_jit_steps - -# def validate_batch_size(self, batch_size: int) -> int: -# if batch_size > self.n_data: -# msg = ( -# f"requested batch size {batch_size} is larger than the number of data" -# f" points {self.n_data}. Setting batch size = {self.n_data}" -# ) -# print("Warning: " + msg) -# log.warning(msg) -# batch_size = self.n_data -# return batch_size - -# def prepare_data(self, i): -# inputs = {k: v[i] for k, v in self.inputs.items()} -# idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) -# inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) - -# zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] -# inputs["positions"] = np.pad( -# inputs["positions"], ((0, zeros_to_add), (0, 0)), "constant" -# ) -# inputs["numbers"] = np.pad( -# inputs["numbers"], (0, zeros_to_add), "constant" -# ).astype(np.int16) -# inputs["n_atoms"] = np.pad( -# inputs["n_atoms"], (0, zeros_to_add), "constant" -# ).astype(np.int16) - -# if not self.labels: -# return inputs - -# labels = {k: v[i] for k, v in self.labels.items()} -# if "forces" in labels: -# labels["forces"] = np.pad( -# labels["forces"], ((0, zeros_to_add), (0, 0)), "constant" -# ) - -# inputs = {k: tf.constant(v) for k, v in inputs.items()} -# labels = {k: tf.constant(v) for k, v in labels.items()} -# return (inputs, labels) - -# def enqueue(self, num_elements): -# for _ in range(num_elements): -# data = self.prepare_data(self.count) -# self.buffer.append(data) -# self.count += 1 - -# def __iter__(self): -# epoch = 0 -# while epoch < self.n_epochs or len(self.buffer) > 0: -# yield self.buffer.popleft() - -# space = self.buffer_size - len(self.buffer) -# if self.count + space > self.n_data: -# space = self.n_data - self.count - -# if self.count >= self.n_data and epoch < self.n_epochs: -# epoch += 1 -# self.count = 0 -# self.enqueue(space) - -# def make_signature(self) -> tf.TensorSpec: -# input_signature = {} -# input_signature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") -# input_signature["numbers"] = tf.TensorSpec( -# (self.max_atoms,), dtype=tf.int16, name="numbers" -# ) -# input_signature["positions"] = tf.TensorSpec( -# (self.max_atoms, 3), dtype=tf.float64, name="positions" -# ) -# input_signature["box"] = tf.TensorSpec((3, 3), dtype=tf.float64, name="box") -# input_signature["idx"] = tf.TensorSpec( -# (2, self.max_nbrs), dtype=tf.int16, name="idx" -# ) -# input_signature["offsets"] = tf.TensorSpec( -# (self.max_nbrs, 3), dtype=tf.float64, name="offsets" -# ) - -# if not self.labels: -# return input_signature - -# label_signature = {} -# if "energy" in self.labels.keys(): -# label_signature["energy"] = tf.TensorSpec((), dtype=tf.float64, name="energy") -# if "forces" in self.labels.keys(): -# label_signature["forces"] = tf.TensorSpec( -# (self.max_atoms, 3), dtype=tf.float64, name="forces" -# ) -# if "stress" in self.labels.keys(): -# label_signature["stress"] = tf.TensorSpec( -# (3, 3), dtype=tf.float64, name="stress" -# ) -# signature = (input_signature, label_signature) -# return signature - -# def init_input(self) -> Dict[str, np.ndarray]: -# """Returns first batch of inputs and labels to init the model.""" -# positions = self.sample_atoms.positions -# box = self.sample_atoms.cell.array -# idx, offsets = compute_nl(positions, box, self.cutoff) -# inputs = ( -# positions, -# self.sample_atoms.numbers, -# idx, -# box, -# offsets, -# ) - -# inputs = jax.tree_map(lambda x: jnp.array(x), inputs) -# return inputs, np.array(box) - -# def shuffle_and_batch(self): -# """Shuffles and batches the inputs/labels. This function prepares the -# inputs and labels for the whole training and prefetches the data. - -# Returns -# ------- -# ds : -# Iterator that returns inputs and labels of one batch in each step. -# """ -# ds = tf.data.Dataset.from_generator( -# lambda: self, output_signature=self.make_signature() -# ) - -# ds = ds.shuffle( -# buffer_size=self.buffer_size, reshuffle_each_iteration=True -# ).batch(batch_size=self.batch_size) -# if self.n_jit_steps > 1: -# ds = ds.batch(batch_size=self.n_jit_steps) -# ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) -# return ds - -# def batch(self) -> Iterator[jax.Array]: -# ds = tf.data.Dataset.from_generator( -# lambda: self, output_signature=self.make_signature() -# ) -# ds = ds.batch(batch_size=self.batch_size) -# ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) -# return ds - - class InMemoryDataset: def __init__( self, @@ -268,7 +82,7 @@ def steps_per_epoch(self) -> int: data are dropped in each epoch. """ return self.n_data // self.batch_size // self.n_jit_steps - + def validate_batch_size(self, batch_size: int) -> int: if batch_size > self.n_data: msg = ( @@ -279,7 +93,7 @@ def validate_batch_size(self, batch_size: int) -> int: log.warning(msg) batch_size = self.n_data return batch_size - + def prepare_data(self, i): inputs = {k: v[i] for k, v in self.inputs.items()} idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) @@ -315,15 +129,6 @@ def enqueue(self, num_elements): self.buffer.append(data) self.count += 1 - def __iter__(self): - while self.count < self.n_data or len(self.buffer) > 0: - yield self.buffer.popleft() - - space = self.buffer_size - len(self.buffer) - if self.count + space > self.n_data: - space = self.n_data - self.count - self.enqueue(space) - def make_signature(self) -> tf.TensorSpec: input_signature = {} input_signature["n_atoms"] = tf.TensorSpec((), dtype=tf.int16, name="n_atoms") @@ -373,6 +178,32 @@ def init_input(self) -> Dict[str, np.ndarray]: inputs = jax.tree_map(lambda x: jnp.array(x), inputs) return inputs, np.array(box) + + def __iter__(self): + raise NotImplementedError + + def shuffle_and_batch(self): + raise NotImplementedError + + def batch(self) -> Iterator[jax.Array]: + raise NotImplementedError + + def cleanup(self): + pass + + +class CachedInMemoryDataset(InMemoryDataset): + + def __iter__(self): + while self.count < self.n_data or len(self.buffer) > 0: + yield self.buffer.popleft() + + space = self.buffer_size - len(self.buffer) + if self.count + space > self.n_data: + space = self.n_data - self.count + self.enqueue(space) + + def shuffle_and_batch(self): """Shuffles and batches the inputs/labels. This function prepares the @@ -409,4 +240,55 @@ def cleanup(self): index_file = self.file.parent / f"{self.file.name}.index" index_file.unlink() - \ No newline at end of file + + +class OTFInMemoryDataset(InMemoryDataset): + + def __iter__(self): + epoch = 0 + while epoch < self.n_epochs or len(self.buffer) > 0: + yield self.buffer.popleft() + + space = self.buffer_size - len(self.buffer) + if self.count + space > self.n_data: + space = self.n_data - self.count + + if self.count >= self.n_data and epoch < self.n_epochs: + epoch += 1 + self.count = 0 + self.enqueue(space) + + def shuffle_and_batch(self): + """Shuffles and batches the inputs/labels. This function prepares the + inputs and labels for the whole training and prefetches the data. + + Returns + ------- + ds : + Iterator that returns inputs and labels of one batch in each step. + """ + ds = tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() + ) + + ds = ds.shuffle( + buffer_size=self.buffer_size, reshuffle_each_iteration=True + ).batch(batch_size=self.batch_size) + if self.n_jit_steps > 1: + ds = ds.batch(batch_size=self.n_jit_steps) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + return ds + + def batch(self) -> Iterator[jax.Array]: + ds = tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() + ) + ds = ds.batch(batch_size=self.batch_size) + ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + return ds + + +dataset_dict = { + "cached": CachedInMemoryDataset, + "otf": OTFInMemoryDataset, +} \ No newline at end of file diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 73f27658..69ef95f6 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -11,7 +11,7 @@ from matscipy.neighbours import neighbour_list from tqdm import trange -from apax.data.input_pipeline import InMemoryDataset +from apax.data.input_pipeline import OTFInMemoryDataset from apax.model import ModelBuilder from apax.train.checkpoints import check_for_ensemble, restore_parameters from apax.utils.jax_md_reduced import partition, quantity, space @@ -256,7 +256,7 @@ def batch_eval( """ if self.model is None: self.initialize(atoms_list[0]) - dataset = InMemoryDataset( + dataset = OTFInMemoryDataset( atoms_list, self.model_config.model.r_max, batch_size, diff --git a/apax/train/eval.py b/apax/train/eval.py index b7d69700..f15a6da3 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -8,7 +8,7 @@ from tqdm import trange from apax.config import parse_config -from apax.data.input_pipeline import InMemoryDataset +from apax.data.input_pipeline import OTFInMemoryDataset from apax.model import ModelBuilder from apax.train.callbacks import initialize_callbacks from apax.train.checkpoints import restore_single_parameters @@ -122,7 +122,7 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): Metrics = initialize_metrics(config.metrics) atoms_list = load_test_data(config, model_version_path, eval_path, n_test) - test_ds = InMemoryDataset( + test_ds = OTFInMemoryDataset( atoms_list, config.model.r_max, config.data.valid_batch_size ) diff --git a/apax/train/run.py b/apax/train/run.py index 0dee0f08..cb7fb60a 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -4,9 +4,9 @@ import jax -from apax.config import LossConfig, parse_config +from apax.config import LossConfig, parse_config, Config from apax.data.initialization import load_data_files -from apax.data.input_pipeline import InMemoryDataset +from apax.data.input_pipeline import dataset_dict from apax.data.statistics import compute_scale_shift_parameters from apax.model import ModelBuilder from apax.optimizer import get_opt @@ -50,10 +50,12 @@ def initialize_loss_fn(loss_config_list: List[LossConfig]) -> LossCollection: loss_funcs.append(Loss(**loss.model_dump())) return LossCollection(loss_funcs) -def initialize_datasets(config): +def initialize_datasets(config: Config): train_raw_ds, val_raw_ds = load_data_files(config.data) - train_ds = InMemoryDataset( + Dataset = dataset_dict[config.data.ds_type] + + train_ds = Dataset( train_raw_ds, config.model.r_max, config.data.batch_size, @@ -63,7 +65,7 @@ def initialize_datasets(config): pre_shuffle=True, cache_path=config.data.model_version_path, ) - val_ds = InMemoryDataset( + val_ds = Dataset( val_raw_ds, config.model.r_max, config.data.valid_batch_size, config.n_epochs, cache_path=config.data.model_version_path, ) ds_stats = compute_scale_shift_parameters( From 90c9f6918719170ac1a22827f2d2d8ae79367659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 29 Mar 2024 13:19:35 +0100 Subject: [PATCH 124/192] remove douple prinitng of BS warning --- apax/data/input_pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 1a014c55..07cee803 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -89,7 +89,6 @@ def validate_batch_size(self, batch_size: int) -> int: f"requested batch size {batch_size} is larger than the number of data" f" points {self.n_data}. Setting batch size = {self.n_data}" ) - print("Warning: " + msg) log.warning(msg) batch_size = self.n_data return batch_size From 07c86b55b417e4c59bdb33289f024f66eb6338c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 29 Mar 2024 13:20:01 +0100 Subject: [PATCH 125/192] filter erroneos TF warning --- apax/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apax/__init__.py b/apax/__init__.py index 7438bf4a..bc72f84c 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -3,6 +3,7 @@ import jax os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' jax.config.update("jax_enable_x64", True) from apax.utils.helpers import setup_ase From 731592c7456a723dfa36afc95eae1f5f0d643417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 29 Mar 2024 13:22:12 +0100 Subject: [PATCH 126/192] linting --- apax/__init__.py | 2 +- apax/data/input_pipeline.py | 42 ++++++++++++++++++++----------------- apax/train/run.py | 10 ++++++--- apax/train/trainer.py | 11 +++++----- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/apax/__init__.py b/apax/__init__.py index bc72f84c..de4b9e6e 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -3,7 +3,7 @@ import jax os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" -os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' +os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" jax.config.update("jax_enable_x64", True) from apax.utils.helpers import setup_ase diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 07cee803..082415a0 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -1,9 +1,9 @@ import logging +import uuid from collections import deque +from pathlib import Path from random import shuffle from typing import Dict, Iterator -import uuid -from pathlib import Path import jax import jax.numpy as jnp @@ -46,7 +46,7 @@ def __init__( n_jit_steps=1, pre_shuffle=False, ignore_labels=False, - cache_path = "." + cache_path=".", ) -> None: if pre_shuffle: shuffle(atoms) @@ -82,7 +82,7 @@ def steps_per_epoch(self) -> int: data are dropped in each epoch. """ return self.n_data // self.batch_size // self.n_jit_steps - + def validate_batch_size(self, batch_size: int) -> int: if batch_size > self.n_data: msg = ( @@ -92,7 +92,7 @@ def validate_batch_size(self, batch_size: int) -> int: log.warning(msg) batch_size = self.n_data return batch_size - + def prepare_data(self, i): inputs = {k: v[i] for k, v in self.inputs.items()} idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) @@ -177,7 +177,7 @@ def init_input(self) -> Dict[str, np.ndarray]: inputs = jax.tree_map(lambda x: jnp.array(x), inputs) return inputs, np.array(box) - + def __iter__(self): raise NotImplementedError @@ -192,7 +192,6 @@ def cleanup(self): class CachedInMemoryDataset(InMemoryDataset): - def __iter__(self): while self.count < self.n_data or len(self.buffer) > 0: yield self.buffer.popleft() @@ -202,8 +201,6 @@ def __iter__(self): space = self.n_data - self.count self.enqueue(space) - - def shuffle_and_batch(self): """Shuffles and batches the inputs/labels. This function prepares the inputs and labels for the whole training and prefetches the data. @@ -213,9 +210,13 @@ def shuffle_and_batch(self): ds : Iterator that returns inputs and labels of one batch in each step. """ - ds = tf.data.Dataset.from_generator( - lambda: self, output_signature=self.make_signature() - ).cache(self.file.as_posix()).repeat(self.n_epochs) + ds = ( + tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() + ) + .cache(self.file.as_posix()) + .repeat(self.n_epochs) + ) ds = ds.shuffle( buffer_size=self.buffer_size, reshuffle_each_iteration=True @@ -226,13 +227,17 @@ def shuffle_and_batch(self): return ds def batch(self) -> Iterator[jax.Array]: - ds = tf.data.Dataset.from_generator( - lambda: self, output_signature=self.make_signature() - ).cache(self.file.as_posix()).repeat(self.n_epochs) + ds = ( + tf.data.Dataset.from_generator( + lambda: self, output_signature=self.make_signature() + ) + .cache(self.file.as_posix()) + .repeat(self.n_epochs) + ) ds = ds.batch(batch_size=self.batch_size) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) return ds - + def cleanup(self): for p in self.file.parent.glob(f"{self.file.name}.data*"): p.unlink() @@ -242,7 +247,6 @@ def cleanup(self): class OTFInMemoryDataset(InMemoryDataset): - def __iter__(self): epoch = 0 while epoch < self.n_epochs or len(self.buffer) > 0: @@ -285,9 +289,9 @@ def batch(self) -> Iterator[jax.Array]: ds = ds.batch(batch_size=self.batch_size) ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) return ds - + dataset_dict = { "cached": CachedInMemoryDataset, "otf": OTFInMemoryDataset, -} \ No newline at end of file +} diff --git a/apax/train/run.py b/apax/train/run.py index cb7fb60a..fe408ab6 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -4,7 +4,7 @@ import jax -from apax.config import LossConfig, parse_config, Config +from apax.config import Config, LossConfig, parse_config from apax.data.initialization import load_data_files from apax.data.input_pipeline import dataset_dict from apax.data.statistics import compute_scale_shift_parameters @@ -50,6 +50,7 @@ def initialize_loss_fn(loss_config_list: List[LossConfig]) -> LossCollection: loss_funcs.append(Loss(**loss.model_dump())) return LossCollection(loss_funcs) + def initialize_datasets(config: Config): train_raw_ds, val_raw_ds = load_data_files(config.data) @@ -66,7 +67,11 @@ def initialize_datasets(config: Config): cache_path=config.data.model_version_path, ) val_ds = Dataset( - val_raw_ds, config.model.r_max, config.data.valid_batch_size, config.n_epochs, cache_path=config.data.model_version_path, + val_raw_ds, + config.model.r_max, + config.data.valid_batch_size, + config.n_epochs, + cache_path=config.data.model_version_path, ) ds_stats = compute_scale_shift_parameters( train_ds.inputs, @@ -79,7 +84,6 @@ def initialize_datasets(config: Config): return train_ds, val_ds, ds_stats - def run(user_config, log_level="error"): config = parse_config(user_config) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 7575d23e..6d6bc0f0 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -1,6 +1,5 @@ import functools import logging -from pathlib import Path import time from functools import partial from typing import Callable, Optional @@ -108,10 +107,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From af320db5f4e7048b9b88aa31e447874d20f61747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 2 Apr 2024 11:01:19 +0200 Subject: [PATCH 127/192] implemented huber loss --- apax/config/train_config.py | 4 +- apax/train/loss.py | 59 +++++++++++++++++------------ tests/unit_tests/train/test_loss.py | 2 +- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 5733dec8..3cd5f57c 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -229,8 +229,10 @@ class LossConfig(BaseModel, extra="forbid"): """ name: str - loss_type: str = "structures" + loss_type: str = "mse" weight: NonNegativeFloat = 1.0 + atoms_exponent: NonNegativeFloat = 1 + parameters: dict = {} class CallbackConfig(BaseModel, frozen=True, extra="forbid"): diff --git a/apax/train/loss.py b/apax/train/loss.py index cd28786e..c2e575d3 100644 --- a/apax/train/loss.py +++ b/apax/train/loss.py @@ -8,7 +8,7 @@ def weighted_squared_error( - label: jnp.array, prediction: jnp.array, divisor: float = 1.0 + label: jnp.array, prediction: jnp.array, divisor: float = 1.0, parameters: dict = {} ) -> jnp.array: """ Squared error function that allows weighting of @@ -17,8 +17,23 @@ def weighted_squared_error( return (label - prediction) ** 2 / divisor +def weighted_huber_loss( + label: jnp.array, prediction: jnp.array, divisor: float = 1.0, parameters: dict = {} +) -> jnp.array: + """ + Huber loss function that allows weighting of + individual contributions by the number of atoms in the system. + """ + if "delta" not in parameters.keys(): + raise KeyError("Huber loss function requires 'delta' parameter") + delta = parameters["delta"] + diff = jnp.abs(label - prediction) + loss = jnp.where(diff > delta, delta * (diff - 0.5 * delta), 0.5 * diff**2) + return loss / divisor + + def force_angle_loss( - label: jnp.array, prediction: jnp.array, divisor: float = 1.0 + label: jnp.array, prediction: jnp.array, divisor: float = 1.0, parameters: dict = {} ) -> jnp.array: """ Consine similarity loss function. Contributions are summed in `Loss`. @@ -28,7 +43,7 @@ def force_angle_loss( def force_angle_div_force_label( - label: jnp.array, prediction: jnp.array, divisor: float = 1.0 + label: jnp.array, prediction: jnp.array, divisor: float = 1.0, parameters: dict = {} ): """ Consine similarity loss function weighted by the norm of the force labels. @@ -41,7 +56,7 @@ def force_angle_div_force_label( def force_angle_exponential_weight( - label: jnp.array, prediction: jnp.array, divisor: float = 1.0 + label: jnp.array, prediction: jnp.array, divisor: float = 1.0, parameters: dict = {} ) -> jnp.array: """ Consine similarity loss function exponentially scaled by the norm of the force labels. @@ -52,7 +67,7 @@ def force_angle_exponential_weight( return (1.0 - dotp) * jnp.exp(-F_0_norm) / divisor -def stress_tril(label, prediction, divisor=1.0): +def stress_tril(label, prediction, divisor=1.0, parameters: dict = {}): idxs = jnp.tril_indices(3) label_tril = label[:, idxs[0], idxs[1]] prediction_tril = prediction[:, idxs[0], idxs[1]] @@ -60,9 +75,8 @@ def stress_tril(label, prediction, divisor=1.0): loss_functions = { - "molecules": weighted_squared_error, - "structures": weighted_squared_error, - "vibrations": weighted_squared_error, + "mse": weighted_squared_error, + "huber": weighted_huber_loss, "cosine_sim": force_angle_loss, "cosine_sim_div_magnitude": force_angle_div_force_label, "cosine_sim_exp_magnitude": force_angle_exponential_weight, @@ -80,6 +94,8 @@ class Loss: name: str loss_type: str weight: float = 1.0 + atoms_exponent: float = 1.0 + parameters: dict = dataclasses.field(default_factory=lambda: {}) def __post_init__(self): if self.loss_type not in loss_functions.keys(): @@ -94,25 +110,18 @@ def __post_init__(self): def __call__(self, inputs: dict, prediction: dict, label: dict) -> float: # TODO we may want to insert an additional `mask` argument for this method divisor = self.determine_divisor(inputs["n_atoms"]) - loss = self.loss_fn(label[self.name], prediction[self.name], divisor=divisor) - return self.weight * jnp.sum(jnp.mean(loss, axis=0)) + batch_losses = self.loss_fn( + label[self.name], prediction[self.name], divisor, self.parameters + ) + loss = self.weight * jnp.sum(jnp.mean(batch_losses, axis=0)) + return loss def determine_divisor(self, n_atoms: jnp.array) -> jnp.array: - divisor_id = self.name + "_" + self.loss_type - divisor_dict = { - "energy_structures": n_atoms**2, - "energy_vibrations": n_atoms, - "forces_structures": einops.repeat(n_atoms, "batch -> batch 1 1"), - "forces_cosine_sim": einops.repeat(n_atoms, "batch -> batch 1 1"), - "cosine_sim_div_magnitude": einops.repeat(n_atoms, "batch -> batch 1 1"), - "forces_cosine_sim_exp_magnitude": einops.repeat( - n_atoms, "batch -> batch 1 1" - ), - "stress_structures": einops.repeat(n_atoms**2, "batch -> batch 1 1"), - "stress_tril": einops.repeat(n_atoms**2, "batch -> batch 1 1"), - "stress_vibrations": einops.repeat(n_atoms, "batch -> batch 1 1"), - } - divisor = divisor_dict.get(divisor_id, jnp.array(1.0)) + # shape: batch + divisor = n_atoms**self.atoms_exponent + + if self.name in ["forces", "stress"]: + divisor = einops.repeat(divisor, "batch -> batch 1 1") return divisor diff --git a/tests/unit_tests/train/test_loss.py b/tests/unit_tests/train/test_loss.py index 26c18bc1..b39aac4c 100644 --- a/tests/unit_tests/train/test_loss.py +++ b/tests/unit_tests/train/test_loss.py @@ -68,7 +68,7 @@ def test_force_angle_loss(): def test_force_loss(): name = "forces" - loss_type = "structures" + loss_type = "mse" weight = 1 inputs = { "n_atoms": jnp.array([2]), From dd8f601d21c7266a2bd96752f28fe7435a105018 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:09:06 +0000 Subject: [PATCH 128/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 6d6bc0f0..8c040a3f 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,12 +107,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 69becc1af251559eec871064c2b315ac65d88c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Tue, 2 Apr 2024 11:27:06 +0200 Subject: [PATCH 129/192] implemented yaml autocompletion via PyDantic json schemata --- .gitignore | 1 + README.md | 32 +++++++++++++++++++++++++++++--- apax/cli/apax_app.py | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e6981eda..041b225d 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ tmp/ .traj .h5 events.out.* +*.schema.json # Translations *.mo diff --git a/README.md b/README.md index 16d78cca..dc4b76c8 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,14 @@ See the [Jax installation instructions](https://github.com/google/jax#installati In order to train a model, you need to run -```python +```bash apax train config.yaml ``` We offer some input file templates to get new users started as quickly as possible. Simply run the following commands and add the appropriate entries in the marked fields -```python +```bash apax template train # use --full for a template with all input options ``` @@ -79,7 +79,7 @@ The documentation can convenienty be accessed by running `apax docs`. There are two ways in which `apax` models can be used for molecular dynamics out of the box. High performance NVT simulations using JaxMD can be started with the CLI by running -```python +```bash apax md config.yaml md_config.yaml ``` @@ -88,6 +88,32 @@ A template command for MD input files is provided as well. The second way is to use the ASE calculator provided in `apax.md`. +## Input File Auto-Completion + +use the following command to generate JSON schemata for training and validation files: + +```bash +apax schema +``` + +If you are using VSCode, you can utilize them to lint and autocomplete your input files by including them in `.vscode/settings.json` + +```json +{ + "yaml.schemas": { + + "/absolute/path/to/apaxtrain.schema.json": [ + "train.yaml" + ] + , + "/absolute/path/to/apaxmd.schema.json": [ + "md.yaml" + ] + } +} +``` + + ## Authors - Moritz René Schäfer - Nico Segreto diff --git a/apax/cli/apax_app.py b/apax/cli/apax_app.py index 60321662..cd09ea7d 100644 --- a/apax/cli/apax_app.py +++ b/apax/cli/apax_app.py @@ -1,5 +1,6 @@ import importlib.metadata import importlib.resources as pkg_resources +import json import sys from pathlib import Path @@ -93,6 +94,23 @@ def docs(): typer.launch("https://apax.readthedocs.io/en/latest/") +@app.command() +def schema(): + """ + Generating JSON schemata for autocompletion of train/md inputs in VSCode. + """ + console.print("Generating JSON schema") + from apax.config import Config, MDConfig + + train_schema = Config.model_json_schema() + md_schema = MDConfig.model_json_schema() + with open("./apaxtrain.schema.json", "w") as f: + f.write(json.dumps(train_schema, indent=2)) + + with open("./apaxmd.schema.json", "w") as f: + f.write(json.dumps(md_schema, indent=2)) + + @validate_app.command("train") def validate_train_config( config_path: Path = typer.Argument( From d5cafc6c4ec0703c2df4faabaebb3fd232139320 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:29:03 +0000 Subject: [PATCH 130/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc4b76c8..c3ffc31f 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ If you are using VSCode, you can utilize them to lint and autocomplete your inpu ```json { "yaml.schemas": { - + "/absolute/path/to/apaxtrain.schema.json": [ "train.yaml" ] From 5b298f901569753e8bb89bb6adf60bef89bb790a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 3 Apr 2024 18:02:00 +0200 Subject: [PATCH 131/192] added optional mlflow dependency --- poetry.lock | 1825 +++++++++++++++++++++++++++++++++++------------- pyproject.toml | 4 + 2 files changed, 1351 insertions(+), 478 deletions(-) diff --git a/poetry.lock b/poetry.lock index 558ca426..ce5c5a9e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. [[package]] name = "absl-py" @@ -22,6 +22,39 @@ files = [ {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] +[[package]] +name = "alembic" +version = "1.13.1" +description = "A database migration tool for SQLAlchemy." +optional = false +python-versions = ">=3.8" +files = [ + {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, + {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, +] + +[package.dependencies] +Mako = "*" +SQLAlchemy = ">=1.3.0" +typing-extensions = ">=4" + +[package.extras] +tz = ["backports.zoneinfo"] + +[[package]] +name = "aniso8601" +version = "9.0.1" +description = "A library for parsing ISO 8601 strings." +optional = false +python-versions = "*" +files = [ + {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"}, + {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"}, +] + +[package.extras] +dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] + [[package]] name = "annotated-types" version = "0.6.0" @@ -35,20 +68,28 @@ files = [ [[package]] name = "array-record" -version = "0.5.0" +version = "0.5.1" description = "A file format that achieves a new frontier of IO efficiency" optional = false python-versions = ">=3.9" files = [ - {file = "array_record-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940fda50bbd1ac6d5f0c3c3d4c885dc886bfb3622a123a8e8fd798582303d8a"}, - {file = "array_record-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac09a423710864f6225ebc45a307c30b419fde4470d2e5f48ba2b1e99bbe84d3"}, - {file = "array_record-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07330e56e7bb1354b5fb9f974dc3c42e4a3cd6e8dcf4c6e6a8b84db14ee9a8ed"}, + {file = "array_record-0.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9f2e304e59a17af9f5bf2a86b93ad4700d0eeb85d742a884aa38dc0b54dda5b"}, + {file = "array_record-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:897362036f2920093eff3d729c2a6e1844e3077f513d6bd29640cd02f98e07c7"}, + {file = "array_record-0.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ebe99f37e3a797322f4f5cfc6902b5e852012ba2729fac628aad6affb225247"}, + {file = "array_record-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea3969b9f954f6f01ddac64f59eea45392dc4eb8c1bf3d1ca5c9bcfd7f8d46e7"}, + {file = "array_record-0.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f08eea9a4afbfa05fb7fafaa007b89e286a8a27a7775cb80338199576ffe07b4"}, + {file = "array_record-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:248fb29086cb3a6322a5d8b8332d77713a030bc54f0bacdf215a6d3185f73f90"}, + {file = "array_record-0.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ebd7c12c0a159a44c6c8fdaf915036fcddfdfa499a878ddcff9761c6d1af685"}, + {file = "array_record-0.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9922862216a9d3be76fdc27968af1ec0ea20f986329998ba45b0f01ee3e646fa"}, ] [package.dependencies] absl-py = "*" etils = {version = "*", extras = ["epath"]} +[package.extras] +beam = ["apache-beam[gcp] (>=2.50.0)", "google-cloud-storage (>=2.11.0)", "tensorflow (>=2.14.0)"] + [[package]] name = "ase" version = "3.22.1" @@ -153,6 +194,17 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "blinker" +version = "1.7.0" +description = "Fast, simple object-to-object and broadcast signaling" +optional = false +python-versions = ">=3.8" +files = [ + {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, + {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, +] + [[package]] name = "cached-property" version = "1.5.2" @@ -316,13 +368,13 @@ numpy = "*" [[package]] name = "chex" -version = "0.1.85" +version = "0.1.86" description = "Chex: Testing made fun, in JAX!" optional = false python-versions = ">=3.9" files = [ - {file = "chex-0.1.85-py3-none-any.whl", hash = "sha256:32c96719aa94045339174138a6aec14aed2630a8a17fb2633ad3eb868890551d"}, - {file = "chex-0.1.85.tar.gz", hash = "sha256:a27cfe87119d6e1fe24ccc1438a59195e6dc1d6e0e10099fcf618c3f64771faf"}, + {file = "chex-0.1.86-py3-none-any.whl", hash = "sha256:251c20821092323a3d9c28e1cf80e4a58180978bec368f531949bd9847eee568"}, + {file = "chex-0.1.86.tar.gz", hash = "sha256:e8b0f96330eba4144659e1617c0f7a57b161e8cbb021e55c6d5056c7378091d1"}, ] [package.dependencies] @@ -347,6 +399,17 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "cloudpickle" +version = "3.0.0" +description = "Pickler class to extend the standard pickle.Pickler functionality" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"}, + {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"}, +] + [[package]] name = "clu" version = "0.0.7" @@ -413,64 +476,64 @@ files = [ [[package]] name = "contourpy" -version = "1.2.0" +version = "1.2.1" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false python-versions = ">=3.9" files = [ - {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, - {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, - {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, - {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, - {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, - {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, - {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, - {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, - {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, - {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, - {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, -] - -[package.dependencies] -numpy = ">=1.20,<2.0" + {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, + {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, + {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, + {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, + {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, + {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, + {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, + {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, + {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, + {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, +] + +[package.dependencies] +numpy = ">=1.20" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] @@ -589,6 +652,13 @@ files = [ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa42a605d099ee7d41ba2b5fb75e21423951fd26e5d50583a00471238fb3021d"}, {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b7764de0d855338abefc6e3ee9fe40d301668310aa3baea3f778ff051f4393"}, {file = "dm_tree-0.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:a5d819c38c03f0bb5b3b3703c60e4b170355a0fc6b5819325bf3d4ceb3ae7e80"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea9e59e0451e7d29aece402d9f908f2e2a80922bcde2ebfd5dcb07750fcbfee8"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:94d3f0826311f45ee19b75f5b48c99466e4218a0489e81c0f0167bda50cacf22"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:435227cf3c5dc63f4de054cf3d00183790bd9ead4c3623138c74dde7f67f521b"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09964470f76a5201aff2e8f9b26842976de7889300676f927930f6285e256760"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75c5d528bb992981c20793b6b453e91560784215dffb8a5440ba999753c14ceb"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a94aba18a35457a1b5cd716fd7b46c5dafdc4cf7869b4bae665b91c4682a8e"}, + {file = "dm_tree-0.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:96a548a406a6fb15fe58f6a30a57ff2f2aafbf25f05afab00c8f5e5977b6c715"}, {file = "dm_tree-0.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8c60a7eadab64c2278861f56bca320b2720f163dca9d7558103c3b77f2416571"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af4b3d372f2477dcd89a6e717e4a575ca35ccc20cc4454a8a4b6f8838a00672d"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de287fabc464b8734be251e46e06aa9aa1001f34198da2b6ce07bd197172b9cb"}, @@ -613,6 +683,27 @@ files = [ {file = "dm_tree-0.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:8ed3564abed97c806db122c2d3e1a2b64c74a63debe9903aad795167cc301368"}, ] +[[package]] +name = "docker" +version = "7.0.0" +description = "A Python library for the Docker Engine API." +optional = false +python-versions = ">=3.8" +files = [ + {file = "docker-7.0.0-py3-none-any.whl", hash = "sha256:12ba681f2777a0ad28ffbcc846a69c31b4dfd9752b47eb425a274ee269c5e14b"}, + {file = "docker-7.0.0.tar.gz", hash = "sha256:323736fb92cd9418fc5e7133bc953e11a9da04f4483f828b527db553f1e7e5a3"}, +] + +[package.dependencies] +packaging = ">=14.0" +pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} +requests = ">=2.26.0" +urllib3 = ">=1.26.0" + +[package.extras] +ssh = ["paramiko (>=2.4.3)"] +websockets = ["websocket-client (>=1.3.0)"] + [[package]] name = "docutils" version = "0.18.1" @@ -635,6 +726,17 @@ files = [ {file = "einops-0.6.1.tar.gz", hash = "sha256:f95f8d00f4ded90dbc4b19b6f98b177332614b0357dde66997f3ae5d474dc8c8"}, ] +[[package]] +name = "entrypoints" +version = "0.4" +description = "Discover and load entry points from installed packages." +optional = false +python-versions = ">=3.6" +files = [ + {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, + {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, +] + [[package]] name = "etils" version = "1.7.0" @@ -647,9 +749,11 @@ files = [ ] [package.dependencies] +absl-py = {version = "*", optional = true, markers = "extra == \"etqdm\""} fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} numpy = {version = "*", optional = true, markers = "extra == \"enp\""} +tqdm = {version = "*", optional = true, markers = "extra == \"etqdm\""} typing_extensions = {version = "*", optional = true, markers = "extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} @@ -703,18 +807,18 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.13.1" +version = "3.13.3" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"}, + {file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -733,26 +837,48 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.9.0,<2.10.0" pyflakes = ">=2.5.0,<2.6.0" +[[package]] +name = "flask" +version = "3.0.2" +description = "A simple framework for building complex web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "flask-3.0.2-py3-none-any.whl", hash = "sha256:3232e0e9c850d781933cf0207523d1ece087eb8d87b23777ae38456e2fbe7c6e"}, + {file = "flask-3.0.2.tar.gz", hash = "sha256:822c03f4b799204250a7ee84b1eddc40665395333973dfb9deebfe425fefcb7d"}, +] + +[package.dependencies] +blinker = ">=1.6.2" +click = ">=8.1.3" +itsdangerous = ">=2.1.2" +Jinja2 = ">=3.1.2" +Werkzeug = ">=3.0.0" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + [[package]] name = "flatbuffers" -version = "23.5.26" +version = "24.3.25" description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" files = [ - {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, - {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, + {file = "flatbuffers-24.3.25-py2.py3-none-any.whl", hash = "sha256:8dbdec58f935f3765e4f7f3cf635ac3a77f83568138d6a2311f524ec96364812"}, + {file = "flatbuffers-24.3.25.tar.gz", hash = "sha256:de2ec5b203f21441716617f38443e0a8ebf3d25bf0d9c0bb0ce68fa00ad546a4"}, ] [[package]] name = "flax" -version = "0.8.1" +version = "0.8.2" description = "Flax: A neural network library for JAX designed for flexibility" optional = false python-versions = ">=3.9" files = [ - {file = "flax-0.8.1-py3-none-any.whl", hash = "sha256:8cf9ef11859eef252470377556a8cc48db287fc6647407ab34f1fc01461925dd"}, - {file = "flax-0.8.1.tar.gz", hash = "sha256:ce3d99e9b4c0d2e4d9fc28bc56cced8ba953adfd695aabd24f096b4c8a7e2f92"}, + {file = "flax-0.8.2-py3-none-any.whl", hash = "sha256:911d83e01380fdb3135c309e70981aabd15e7ca038014d7989ddc3cfaf4d0d45"}, + {file = "flax-0.8.2.tar.gz", hash = "sha256:1c4e43ac3cb32e8e15c733cfa3df8d827b61d9ce29b50a7035920bfe9fdaa5b0"}, ] [package.dependencies] @@ -775,53 +901,53 @@ testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9)", "einops", "gymna [[package]] name = "fonttools" -version = "4.49.0" +version = "4.50.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"}, - {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"}, - {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"}, - {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"}, - {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"}, - {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"}, - {file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"}, - {file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"}, - {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"}, - {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"}, - {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"}, - {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"}, - {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"}, - {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"}, - {file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"}, - {file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"}, - {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"}, - {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"}, - {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"}, - {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"}, - {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"}, - {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"}, - {file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"}, - {file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"}, - {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"}, - {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"}, - {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"}, - {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"}, - {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"}, - {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"}, - {file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"}, - {file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"}, - {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"}, - {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"}, - {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"}, - {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"}, - {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"}, - {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"}, - {file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"}, - {file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"}, - {file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"}, - {file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"}, + {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effd303fb422f8ce06543a36ca69148471144c534cc25f30e5be752bc4f46736"}, + {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7913992ab836f621d06aabac118fc258b9947a775a607e1a737eb3a91c360335"}, + {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0a1c5bd2f63da4043b63888534b52c5a1fd7ae187c8ffc64cbb7ae475b9dab"}, + {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d40fc98540fa5360e7ecf2c56ddf3c6e7dd04929543618fd7b5cc76e66390562"}, + {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fff65fbb7afe137bac3113827855e0204482727bddd00a806034ab0d3951d0d"}, + {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1aeae3dd2ee719074a9372c89ad94f7c581903306d76befdaca2a559f802472"}, + {file = "fonttools-4.50.0-cp310-cp310-win32.whl", hash = "sha256:e9623afa319405da33b43c85cceb0585a6f5d3a1d7c604daf4f7e1dd55c03d1f"}, + {file = "fonttools-4.50.0-cp310-cp310-win_amd64.whl", hash = "sha256:778c5f43e7e654ef7fe0605e80894930bc3a7772e2f496238e57218610140f54"}, + {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3dfb102e7f63b78c832e4539969167ffcc0375b013080e6472350965a5fe8048"}, + {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e58fe34cb379ba3d01d5d319d67dd3ce7ca9a47ad044ea2b22635cd2d1247fc"}, + {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c673ab40d15a442a4e6eb09bf007c1dda47c84ac1e2eecbdf359adacb799c24"}, + {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3ac35cdcd1a4c90c23a5200212c1bb74fa05833cc7c14291d7043a52ca2aaa"}, + {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8844e7a2c5f7ecf977e82eb6b3014f025c8b454e046d941ece05b768be5847ae"}, + {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f849bd3c5c2249b49c98eca5aaebb920d2bfd92b3c69e84ca9bddf133e9f83f0"}, + {file = "fonttools-4.50.0-cp311-cp311-win32.whl", hash = "sha256:39293ff231b36b035575e81c14626dfc14407a20de5262f9596c2cbb199c3625"}, + {file = "fonttools-4.50.0-cp311-cp311-win_amd64.whl", hash = "sha256:c33d5023523b44d3481624f840c8646656a1def7630ca562f222eb3ead16c438"}, + {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b4a886a6dbe60100ba1cd24de962f8cd18139bd32808da80de1fa9f9f27bf1dc"}, + {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b2ca1837bfbe5eafa11313dbc7edada79052709a1fffa10cea691210af4aa1fa"}, + {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0493dd97ac8977e48ffc1476b932b37c847cbb87fd68673dee5182004906828"}, + {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77844e2f1b0889120b6c222fc49b2b75c3d88b930615e98893b899b9352a27ea"}, + {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3566bfb8c55ed9100afe1ba6f0f12265cd63a1387b9661eb6031a1578a28bad1"}, + {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:35e10ddbc129cf61775d58a14f2d44121178d89874d32cae1eac722e687d9019"}, + {file = "fonttools-4.50.0-cp312-cp312-win32.whl", hash = "sha256:cc8140baf9fa8f9b903f2b393a6c413a220fa990264b215bf48484f3d0bf8710"}, + {file = "fonttools-4.50.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ccc85fd96373ab73c59833b824d7a73846670a0cb1f3afbaee2b2c426a8f931"}, + {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e270a406219af37581d96c810172001ec536e29e5593aa40d4c01cca3e145aa6"}, + {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac2463de667233372e9e1c7e9de3d914b708437ef52a3199fdbf5a60184f190c"}, + {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47abd6669195abe87c22750dbcd366dc3a0648f1b7c93c2baa97429c4dc1506e"}, + {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:074841375e2e3d559aecc86e1224caf78e8b8417bb391e7d2506412538f21adc"}, + {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0743fd2191ad7ab43d78cd747215b12033ddee24fa1e088605a3efe80d6984de"}, + {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3d7080cce7be5ed65bee3496f09f79a82865a514863197ff4d4d177389e981b0"}, + {file = "fonttools-4.50.0-cp38-cp38-win32.whl", hash = "sha256:a467ba4e2eadc1d5cc1a11d355abb945f680473fbe30d15617e104c81f483045"}, + {file = "fonttools-4.50.0-cp38-cp38-win_amd64.whl", hash = "sha256:f77e048f805e00870659d6318fd89ef28ca4ee16a22b4c5e1905b735495fc422"}, + {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b6245eafd553c4e9a0708e93be51392bd2288c773523892fbd616d33fd2fda59"}, + {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a4062cc7e8de26f1603323ef3ae2171c9d29c8a9f5e067d555a2813cd5c7a7e0"}, + {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34692850dfd64ba06af61e5791a441f664cb7d21e7b544e8f385718430e8f8e4"}, + {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678dd95f26a67e02c50dcb5bf250f95231d455642afbc65a3b0bcdacd4e4dd38"}, + {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f2ce7b0b295fe64ac0a85aef46a0f2614995774bd7bc643b85679c0283287f9"}, + {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d346f4dc2221bfb7ab652d1e37d327578434ce559baf7113b0f55768437fe6a0"}, + {file = "fonttools-4.50.0-cp39-cp39-win32.whl", hash = "sha256:a51eeaf52ba3afd70bf489be20e52fdfafe6c03d652b02477c6ce23c995222f4"}, + {file = "fonttools-4.50.0-cp39-cp39-win_amd64.whl", hash = "sha256:8639be40d583e5d9da67795aa3eeeda0488fb577a1d42ae11a5036f18fb16d93"}, + {file = "fonttools-4.50.0-py3-none-any.whl", hash = "sha256:48fa36da06247aa8282766cfd63efff1bb24e55f020f29a335939ed3844d20d3"}, + {file = "fonttools-4.50.0.tar.gz", hash = "sha256:fa5cf61058c7dbb104c2ac4e782bf1b2016a8cf2f69de6e4dd6a865d2c969bb5"}, ] [package.extras] @@ -840,13 +966,13 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "fsspec" -version = "2024.2.0" +version = "2024.3.1" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8"}, - {file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84"}, + {file = "fsspec-2024.3.1-py3-none-any.whl", hash = "sha256:918d18d41bf73f0e2b261824baeb1b124bcf771767e3a26425cd7dec3332f512"}, + {file = "fsspec-2024.3.1.tar.gz", hash = "sha256:f39780e282d7d117ffb42bb96992f8a90795e4d0fb0f661a70ca39fe9c43ded9"}, ] [package.extras] @@ -901,15 +1027,47 @@ files = [ {file = "gast-0.5.4.tar.gz", hash = "sha256:9c270fe5f4b130969b54174de7db4e764b09b4f7f67ccfc32480e29f78348d97"}, ] +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.43" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] + [[package]] name = "google-auth" -version = "2.28.1" +version = "2.29.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.28.1.tar.gz", hash = "sha256:34fc3046c257cedcf1622fc4b31fc2be7923d9b4d44973d481125ecc50d83885"}, - {file = "google_auth-2.28.1-py2.py3-none-any.whl", hash = "sha256:25141e2d7a14bfcba945f5e9827f98092716e99482562f15306e5b026e21aa72"}, + {file = "google-auth-2.29.0.tar.gz", hash = "sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360"}, + {file = "google_auth-2.29.0-py2.py3-none-any.whl", hash = "sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415"}, ] [package.dependencies] @@ -959,13 +1117,13 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.62.0" +version = "1.63.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, - {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, + {file = "googleapis-common-protos-1.63.0.tar.gz", hash = "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e"}, + {file = "googleapis_common_protos-1.63.0-py2.py3-none-any.whl", hash = "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632"}, ] [package.dependencies] @@ -974,71 +1132,207 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4 [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +[[package]] +name = "graphene" +version = "3.3" +description = "GraphQL Framework for Python" +optional = false +python-versions = "*" +files = [ + {file = "graphene-3.3-py2.py3-none-any.whl", hash = "sha256:bb3810be33b54cb3e6969506671eb72319e8d7ba0d5ca9c8066472f75bf35a38"}, + {file = "graphene-3.3.tar.gz", hash = "sha256:529bf40c2a698954217d3713c6041d69d3f719ad0080857d7ee31327112446b0"}, +] + +[package.dependencies] +aniso8601 = ">=8,<10" +graphql-core = ">=3.1,<3.3" +graphql-relay = ">=3.1,<3.3" + +[package.extras] +dev = ["black (==22.3.0)", "coveralls (>=3.3,<4)", "flake8 (>=4,<5)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"] +test = ["coveralls (>=3.3,<4)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"] + +[[package]] +name = "graphql-core" +version = "3.2.3" +description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, + {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, +] + +[[package]] +name = "graphql-relay" +version = "3.2.0" +description = "Relay library for graphql-core" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"}, + {file = "graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"}, +] + +[package.dependencies] +graphql-core = ">=3.2,<3.3" + +[[package]] +name = "greenlet" +version = "3.0.3" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + [[package]] name = "grpcio" -version = "1.62.0" +version = "1.62.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] + {file = "grpcio-1.62.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:179bee6f5ed7b5f618844f760b6acf7e910988de77a4f75b95bbfaa8106f3c1e"}, + {file = "grpcio-1.62.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:48611e4fa010e823ba2de8fd3f77c1322dd60cb0d180dc6630a7e157b205f7ea"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b2a0e71b0a2158aa4bce48be9f8f9eb45cbd17c78c7443616d00abbe2a509f6d"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbe80577c7880911d3ad65e5ecc997416c98f354efeba2f8d0f9112a67ed65a5"}, + {file = "grpcio-1.62.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f6c693d446964e3292425e1d16e21a97a48ba9172f2d0df9d7b640acb99243"}, + {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:77c339403db5a20ef4fed02e4d1a9a3d9866bf9c0afc77a42234677313ea22f3"}, + {file = "grpcio-1.62.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b5a4ea906db7dec694098435d84bf2854fe158eb3cd51e1107e571246d4d1d70"}, + {file = "grpcio-1.62.1-cp310-cp310-win32.whl", hash = "sha256:4187201a53f8561c015bc745b81a1b2d278967b8de35f3399b84b0695e281d5f"}, + {file = "grpcio-1.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:844d1f3fb11bd1ed362d3fdc495d0770cfab75761836193af166fee113421d66"}, + {file = "grpcio-1.62.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:833379943d1728a005e44103f17ecd73d058d37d95783eb8f0b28ddc1f54d7b2"}, + {file = "grpcio-1.62.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c7fcc6a32e7b7b58f5a7d27530669337a5d587d4066060bcb9dee7a8c833dfb7"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:fa7d28eb4d50b7cbe75bb8b45ed0da9a1dc5b219a0af59449676a29c2eed9698"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48f7135c3de2f298b833be8b4ae20cafe37091634e91f61f5a7eb3d61ec6f660"}, + {file = "grpcio-1.62.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f11fd63365ade276c9d4a7b7df5c136f9030e3457107e1791b3737a9b9ed6a"}, + {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b49fd8fe9f9ac23b78437da94c54aa7e9996fbb220bac024a67469ce5d0825f"}, + {file = "grpcio-1.62.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:482ae2ae78679ba9ed5752099b32e5fe580443b4f798e1b71df412abf43375db"}, + {file = "grpcio-1.62.1-cp311-cp311-win32.whl", hash = "sha256:1faa02530b6c7426404372515fe5ddf66e199c2ee613f88f025c6f3bd816450c"}, + {file = "grpcio-1.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bd90b8c395f39bc82a5fb32a0173e220e3f401ff697840f4003e15b96d1befc"}, + {file = "grpcio-1.62.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b134d5d71b4e0837fff574c00e49176051a1c532d26c052a1e43231f252d813b"}, + {file = "grpcio-1.62.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d1f6c96573dc09d50dbcbd91dbf71d5cf97640c9427c32584010fbbd4c0e0037"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:359f821d4578f80f41909b9ee9b76fb249a21035a061a327f91c953493782c31"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a485f0c2010c696be269184bdb5ae72781344cb4e60db976c59d84dd6354fac9"}, + {file = "grpcio-1.62.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50b09b4dc01767163d67e1532f948264167cd27f49e9377e3556c3cba1268e1"}, + {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3227c667dccbe38f2c4d943238b887bac588d97c104815aecc62d2fd976e014b"}, + {file = "grpcio-1.62.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3952b581eb121324853ce2b191dae08badb75cd493cb4e0243368aa9e61cfd41"}, + {file = "grpcio-1.62.1-cp312-cp312-win32.whl", hash = "sha256:83a17b303425104d6329c10eb34bba186ffa67161e63fa6cdae7776ff76df73f"}, + {file = "grpcio-1.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:6696ffe440333a19d8d128e88d440f91fb92c75a80ce4b44d55800e656a3ef1d"}, + {file = "grpcio-1.62.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:e3393b0823f938253370ebef033c9fd23d27f3eae8eb9a8f6264900c7ea3fb5a"}, + {file = "grpcio-1.62.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:83e7ccb85a74beaeae2634f10eb858a0ed1a63081172649ff4261f929bacfd22"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:882020c87999d54667a284c7ddf065b359bd00251fcd70279ac486776dbf84ec"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a10383035e864f386fe096fed5c47d27a2bf7173c56a6e26cffaaa5a361addb1"}, + {file = "grpcio-1.62.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:960edebedc6b9ada1ef58e1c71156f28689978188cd8cff3b646b57288a927d9"}, + {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:23e2e04b83f347d0aadde0c9b616f4726c3d76db04b438fd3904b289a725267f"}, + {file = "grpcio-1.62.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978121758711916d34fe57c1f75b79cdfc73952f1481bb9583399331682d36f7"}, + {file = "grpcio-1.62.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9084086190cc6d628f282e5615f987288b95457292e969b9205e45b442276407"}, + {file = "grpcio-1.62.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:22bccdd7b23c420a27fd28540fb5dcbc97dc6be105f7698cb0e7d7a420d0e362"}, + {file = "grpcio-1.62.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:8999bf1b57172dbc7c3e4bb3c732658e918f5c333b2942243f10d0d653953ba9"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:d9e52558b8b8c2f4ac05ac86344a7417ccdd2b460a59616de49eb6933b07a0bd"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1714e7bc935780bc3de1b3fcbc7674209adf5208ff825799d579ffd6cd0bd505"}, + {file = "grpcio-1.62.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8842ccbd8c0e253c1f189088228f9b433f7a93b7196b9e5b6f87dba393f5d5d"}, + {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f1e7b36bdff50103af95a80923bf1853f6823dd62f2d2a2524b66ed74103e49"}, + {file = "grpcio-1.62.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bba97b8e8883a8038606480d6b6772289f4c907f6ba780fa1f7b7da7dfd76f06"}, + {file = "grpcio-1.62.1-cp38-cp38-win32.whl", hash = "sha256:a7f615270fe534548112a74e790cd9d4f5509d744dd718cd442bf016626c22e4"}, + {file = "grpcio-1.62.1-cp38-cp38-win_amd64.whl", hash = "sha256:e6c8c8693df718c5ecbc7babb12c69a4e3677fd11de8886f05ab22d4e6b1c43b"}, + {file = "grpcio-1.62.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:73db2dc1b201d20ab7083e7041946910bb991e7e9761a0394bbc3c2632326483"}, + {file = "grpcio-1.62.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:407b26b7f7bbd4f4751dbc9767a1f0716f9fe72d3d7e96bb3ccfc4aace07c8de"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f8de7c8cef9261a2d0a62edf2ccea3d741a523c6b8a6477a340a1f2e417658de"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd5c8a1af40ec305d001c60236308a67e25419003e9bb3ebfab5695a8d0b369"}, + {file = "grpcio-1.62.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0477cb31da67846a33b1a75c611f88bfbcd427fe17701b6317aefceee1b96f"}, + {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:60dcd824df166ba266ee0cfaf35a31406cd16ef602b49f5d4dfb21f014b0dedd"}, + {file = "grpcio-1.62.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:973c49086cabab773525f6077f95e5a993bfc03ba8fc32e32f2c279497780585"}, + {file = "grpcio-1.62.1-cp39-cp39-win32.whl", hash = "sha256:12859468e8918d3bd243d213cd6fd6ab07208195dc140763c00dfe901ce1e1b4"}, + {file = "grpcio-1.62.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7209117bbeebdfa5d898205cc55153a51285757902dd73c47de498ad4d11332"}, + {file = "grpcio-1.62.1.tar.gz", hash = "sha256:6c455e008fa86d9e9a9d85bb76da4277c0d7d9668a3bfa70dbe86e9f3c759947"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.62.1)"] + +[[package]] +name = "gunicorn" +version = "21.2.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.5" +files = [ + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] [[package]] name = "h5py" @@ -1113,20 +1407,39 @@ files = [ {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] +[[package]] +name = "importlib-metadata" +version = "7.1.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] + [[package]] name = "importlib-resources" -version = "6.1.2" +version = "6.4.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, - {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1153,6 +1466,17 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +optional = false +python-versions = ">=3.7" +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] + [[package]] name = "jax" version = "0.4.25" @@ -1227,19 +1551,18 @@ cuda12-pip = ["nvidia-cublas-cu12", "nvidia-cuda-cupti-cu12", "nvidia-cuda-nvcc- [[package]] name = "jaxtyping" -version = "0.2.25" +version = "0.2.28" description = "Type annotations and runtime checking for shape and dtype of JAX arrays, and PyTrees." optional = false python-versions = "~=3.9" files = [ - {file = "jaxtyping-0.2.25-py3-none-any.whl", hash = "sha256:503772cf985ff50bd160d0661266e1628da47cc8b9a302de16f230e07f5ac119"}, - {file = "jaxtyping-0.2.25.tar.gz", hash = "sha256:4ec4bdb6839a67c062e48c27d62d44bf353099d7ff6cd3628b5a511c097ab922"}, + {file = "jaxtyping-0.2.28-py3-none-any.whl", hash = "sha256:4a54eb964087cd46463d9a86c805b4e4f5c20cce5f22049d6f35a26d9f105bd3"}, + {file = "jaxtyping-0.2.28.tar.gz", hash = "sha256:cd20bf1558a90c6d77c589354e35670ecc5b94925ef45bf1c020fde7b44fac8d"}, ] [package.dependencies] numpy = ">=1.20.0" -typeguard = ">=2.13.3,<3" -typing-extensions = ">=3.7.4.1" +typeguard = "2.13.3" [[package]] name = "jinja2" @@ -1258,6 +1581,17 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "joblib" +version = "1.3.2" +description = "Lightweight pipelining with Python functions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"}, + {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"}, +] + [[package]] name = "keras" version = "2.15.0" @@ -1399,22 +1733,20 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "libclang" -version = "16.0.6" +version = "18.1.1" description = "Clang Python Bindings, mirrored from the official LLVM repo: https://github.com/llvm/llvm-project/tree/main/clang/bindings/python, to make the installation process easier." optional = false python-versions = "*" files = [ - {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:88bc7e7b393c32e41e03ba77ef02fdd647da1f764c2cd028e69e0837080b79f6"}, - {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:d80ed5827736ed5ec2bcedf536720476fd9d4fa4c79ef0cb24aea4c59332f361"}, - {file = "libclang-16.0.6-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:da9e47ebc3f0a6d90fb169ef25f9fbcd29b4a4ef97a8b0e3e3a17800af1423f4"}, - {file = "libclang-16.0.6-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1a5ad1e895e5443e205568c85c04b4608e4e973dae42f4dfd9cb46c81d1486b"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:9dcdc730939788b8b69ffd6d5d75fe5366e3ee007f1e36a99799ec0b0c001492"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:8130482120500476a027171f8f3c8dfc2536b591716eea71fc5da22cae13131b"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:1e940048f51d0b0999099a9b78629ab8a64b62af5e9ff1b2b062439c21ee244d"}, - {file = "libclang-16.0.6-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f04e3060ae1f207f234d0608900c99c50edcb743e5e18276d78da2ddd727d39f"}, - {file = "libclang-16.0.6-py2.py3-none-win_amd64.whl", hash = "sha256:daab4a11dae228f1efa9efa3fe638b493b14d8d52c71fb3c7019e2f1df4514c2"}, - {file = "libclang-16.0.6-py2.py3-none-win_arm64.whl", hash = "sha256:4a9acbfd9c135a72f80d5dbff7588dfb0c81458244a89b9e83526e8595880e0a"}, - {file = "libclang-16.0.6.tar.gz", hash = "sha256:4acdde39dfe410c877b4ccc0d4b57eb952100e4ee26bbdf6cfdb88e2033a7d31"}, + {file = "libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5"}, + {file = "libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe"}, + {file = "libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f"}, + {file = "libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb"}, + {file = "libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8"}, + {file = "libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250"}, ] [[package]] @@ -1428,15 +1760,34 @@ files = [ {file = "looseversion-1.3.0.tar.gz", hash = "sha256:ebde65f3f6bb9531a81016c6fef3eb95a61181adc47b7f949e9c0ea47911669e"}, ] +[[package]] +name = "mako" +version = "1.3.2" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, + {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + [[package]] name = "markdown" -version = "3.5.2" +version = "3.6" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, - {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, ] [package.extras] @@ -1682,102 +2033,154 @@ six = "*" [[package]] name = "ml-dtypes" -version = "0.2.0" +version = "0.3.2" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "ml_dtypes-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df6a76e1c8adf484feb138ed323f9f40a7b6c21788f120f7c78bec20ac37ee81"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc29a0524ef5e23a7fbb8d881bdecabeb3fc1d19d9db61785d077a86cb94fab2"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08c391c2794f2aad358e6f4c70785a9a7b1df980ef4c232b3ccd4f6fe39f719"}, - {file = "ml_dtypes-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:75015818a7fccf99a5e8ed18720cb430f3e71a8838388840f4cdf225c036c983"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e70047ec2c83eaee01afdfdabee2c5b0c133804d90d0f7db4dd903360fcc537c"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36d28b8861a8931695e5a31176cad5ae85f6504906650dea5598fbec06c94606"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85ba8e24cf48d456e564688e981cf379d4c8e644db0a2f719b78de281bac2ca"}, - {file = "ml_dtypes-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:832a019a1b6db5c4422032ca9940a990fa104eee420f643713241b3a518977fa"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8faaf0897942c8253dd126662776ba45f0a5861968cf0f06d6d465f8a7bc298a"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b984cddbe8173b545a0e3334fe56ea1a5c3eb67c507f60d0cfde1d3fa8f8c2"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:022d5a4ee6be14569c2a9d1549e16f1ec87ca949681d0dca59995445d5fcdd5b"}, - {file = "ml_dtypes-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:50845af3e9a601810751b55091dee6c2562403fa1cb4e0123675cf3a4fc2c17a"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f00c71c8c63e03aff313bc6a7aeaac9a4f1483a921a6ffefa6d4404efd1af3d0"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80d304c836d73f10605c58ccf7789c171cc229bfb678748adfb7cea2510dfd0e"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32107e7fa9f62db9a5281de923861325211dfff87bd23faefb27b303314635ab"}, - {file = "ml_dtypes-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:1749b60348da71fd3c2ab303fdbc1965958dc50775ead41f5669c932a341cafd"}, - {file = "ml_dtypes-0.2.0.tar.gz", hash = "sha256:6488eb642acaaf08d8020f6de0a38acee7ac324c1e6e92ee0c0fea42422cb797"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7afde548890a92b41c0fed3a6c525f1200a5727205f73dc21181a2726571bb53"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a746fe5fb9cd974a91070174258f0be129c592b93f9ce7df6cc336416c3fbd"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961134ea44c7b8ca63eda902a44b58cd8bd670e21d62e255c81fba0a8e70d9b7"}, + {file = "ml_dtypes-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:6b35c4e8ca957c877ac35c79ffa77724ecc3702a1e4b18b08306c03feae597bb"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:763697ab8a88d47443997a7cdf3aac7340049aed45f7521f6b0ec8a0594821fe"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89b194e9501a92d289c1ffd411380baf5daafb9818109a4f49b0a1b6dce4462"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c34f2ba9660b21fe1034b608308a01be82bbef2a92fb8199f24dc6bad0d5226"}, + {file = "ml_dtypes-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:6604877d567a29bfe7cc02969ae0f2425260e5335505cf5e7fefc3e5465f5655"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:93b78f53431c93953f7850bb1b925a17f0ab5d97527e38a7e865b5b4bc5cfc18"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a17ef2322e60858d93584e9c52a5be7dd6236b056b7fa1ec57f1bb6ba043e33"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8505946df1665db01332d885c2020b4cb9e84a8b1241eb4ba69d59591f65855"}, + {file = "ml_dtypes-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:f47619d978ab1ae7dfdc4052ea97c636c6263e1f19bd1be0e42c346b98d15ff4"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7b3fb3d4f6b39bcd4f6c4b98f406291f0d681a895490ee29a0f95bab850d53c"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a4c3fcbf86fa52d0204f07cfd23947ef05b4ad743a1a988e163caa34a201e5e"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91f8783fd1f2c23fd3b9ee5ad66b785dafa58ba3cdb050c4458021fa4d1eb226"}, + {file = "ml_dtypes-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ba8e1fafc7fff3e643f453bffa7d082df1678a73286ce8187d3e825e776eb94"}, + {file = "ml_dtypes-0.3.2.tar.gz", hash = "sha256:533059bc5f1764fac071ef54598db358c167c51a718f68f5bb55e3dee79d2967"}, ] [package.dependencies] numpy = [ - {version = ">=1.23.3", markers = "python_version > \"3.10\""}, - {version = ">=1.21.2", markers = "python_version > \"3.9\" and python_version <= \"3.10\""}, + {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.2", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] [package.extras] dev = ["absl-py", "pyink", "pylint (>=2.6.0)", "pytest", "pytest-xdist"] +[[package]] +name = "mlflow" +version = "2.11.3" +description = "MLflow: A Platform for ML Development and Productionization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mlflow-2.11.3-py3-none-any.whl", hash = "sha256:6af105162b6f7f2a69cace48c2af7adbecfada5e6386f1ce7d1bbbffd6e09953"}, + {file = "mlflow-2.11.3.tar.gz", hash = "sha256:621b7e311e890b79719c2e7777286d8e08d38dd04d5ab080966990bd4a55febb"}, +] + +[package.dependencies] +alembic = "<1.10.0 || >1.10.0,<2" +click = ">=7.0,<9" +cloudpickle = "<4" +docker = ">=4.0.0,<8" +entrypoints = "<1" +Flask = "<4" +gitpython = ">=3.1.9,<4" +graphene = "<4" +gunicorn = {version = "<22", markers = "platform_system != \"Windows\""} +importlib-metadata = ">=3.7.0,<4.7.0 || >4.7.0,<8" +Jinja2 = [ + {version = ">=2.11,<4", markers = "platform_system != \"Windows\""}, + {version = ">=3.0,<4", markers = "platform_system == \"Windows\""}, +] +markdown = ">=3.3,<4" +matplotlib = "<4" +numpy = "<2" +packaging = "<24" +pandas = "<3" +protobuf = ">=3.12.0,<5" +pyarrow = ">=4.0.0,<16" +pytz = "<2025" +pyyaml = ">=5.1,<7" +querystring-parser = "<2" +requests = ">=2.17.3,<3" +scikit-learn = "<2" +scipy = "<2" +sqlalchemy = ">=1.4.0,<3" +sqlparse = ">=0.4.0,<1" +waitress = {version = "<4", markers = "platform_system == \"Windows\""} + +[package.extras] +aliyun-oss = ["aliyunstoreplugin"] +databricks = ["azure-storage-file-datalake (>12)", "boto3 (>1)", "botocore", "google-cloud-storage (>=1.30.0)"] +extras = ["azureml-core (>=1.2.0)", "boto3", "botocore", "google-cloud-storage (>=1.30.0)", "kubernetes", "mlserver (>=1.2.0,!=1.3.1,<1.4.0)", "mlserver-mlflow (>=1.2.0,!=1.3.1,<1.4.0)", "prometheus-flask-exporter", "pyarrow", "pysftp", "requests-auth-aws-sigv4", "virtualenv"] +gateway = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "pydantic (>=1.0,<3)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<1)"] +genai = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "pydantic (>=1.0,<3)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<1)"] +sqlserver = ["mlflow-dbstore"] +xethub = ["mlflow-xethub"] + [[package]] name = "msgpack" -version = "1.0.7" +version = "1.0.8" description = "MessagePack serializer" optional = false python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"}, - {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"}, - {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"}, - {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"}, - {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"}, - {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"}, - {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"}, - {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"}, - {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"}, - {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"}, - {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"}, - {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] [[package]] @@ -1947,13 +2350,13 @@ test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] [[package]] name = "orbax-checkpoint" -version = "0.4.4" +version = "0.5.7" description = "Orbax Checkpoint" optional = false python-versions = ">=3.9" files = [ - {file = "orbax_checkpoint-0.4.4-py3-none-any.whl", hash = "sha256:e356288d7f62b30519b20ae3c0584743d6598234e4996b4c15bbbd32c13c1f04"}, - {file = "orbax_checkpoint-0.4.4.tar.gz", hash = "sha256:85ab96268b3f39e83809254cb3d55aa5a47c2279d7d3e725bd5f7c2da10a4de9"}, + {file = "orbax_checkpoint-0.5.7-py3-none-any.whl", hash = "sha256:34aa0b206a4cff9ea29acc96f2a913d0616cb5bcd15272a9806bb0238dd7a38c"}, + {file = "orbax_checkpoint-0.5.7.tar.gz", hash = "sha256:de14549b899220a4f445453967c1ac2d7165b815253342587746005f03a9813b"}, ] [package.dependencies] @@ -1966,7 +2369,7 @@ nest_asyncio = "*" numpy = "*" protobuf = "*" pyyaml = "*" -tensorstore = ">=0.1.35" +tensorstore = ">=0.1.51" typing_extensions = "*" [package.extras] @@ -1983,6 +2386,78 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pandas" +version = "2.2.1" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8df8612be9cd1c7797c93e1c5df861b2ddda0b48b08f2c3eaa0702cf88fb5f88"}, + {file = "pandas-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0f573ab277252ed9aaf38240f3b54cfc90fff8e5cab70411ee1d03f5d51f3944"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f02a3a6c83df4026e55b63c1f06476c9aa3ed6af3d89b4f04ea656ccdaaaa359"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c38ce92cb22a4bea4e3929429aa1067a454dcc9c335799af93ba9be21b6beb51"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c2ce852e1cf2509a69e98358e8458775f89599566ac3775e70419b98615f4b06"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53680dc9b2519cbf609c62db3ed7c0b499077c7fefda564e330286e619ff0dd9"}, + {file = "pandas-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:94e714a1cca63e4f5939cdce5f29ba8d415d85166be3441165edd427dc9f6bc0"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f821213d48f4ab353d20ebc24e4faf94ba40d76680642fb7ce2ea31a3ad94f9b"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c70e00c2d894cb230e5c15e4b1e1e6b2b478e09cf27cc593a11ef955b9ecc81a"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97fbb5387c69209f134893abc788a6486dbf2f9e511070ca05eed4b930b1b02"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101d0eb9c5361aa0146f500773395a03839a5e6ecde4d4b6ced88b7e5a1a6403"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7d2ed41c319c9fb4fd454fe25372028dfa417aacb9790f68171b2e3f06eae8cd"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5d3c00557d657c8773ef9ee702c61dd13b9d7426794c9dfeb1dc4a0bf0ebc7"}, + {file = "pandas-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:06cf591dbaefb6da9de8472535b185cba556d0ce2e6ed28e21d919704fef1a9e"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:88ecb5c01bb9ca927ebc4098136038519aa5d66b44671861ffab754cae75102c"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04f6ec3baec203c13e3f8b139fb0f9f86cd8c0b94603ae3ae8ce9a422e9f5bee"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a935a90a76c44fe170d01e90a3594beef9e9a6220021acfb26053d01426f7dc2"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c391f594aae2fd9f679d419e9a4d5ba4bce5bb13f6a989195656e7dc4b95c8f0"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9d1265545f579edf3f8f0cb6f89f234f5e44ba725a34d86535b1a1d38decbccc"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11940e9e3056576ac3244baef2fedade891977bcc1cb7e5cc8f8cc7d603edc89"}, + {file = "pandas-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acf681325ee1c7f950d058b05a820441075b0dd9a2adf5c4835b9bc056bf4fb"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9bd8a40f47080825af4317d0340c656744f2bfdb6819f818e6ba3cd24c0e1397"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df0c37ebd19e11d089ceba66eba59a168242fc6b7155cba4ffffa6eccdfb8f16"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739cc70eaf17d57608639e74d63387b0d8594ce02f69e7a0b046f117974b3019"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d3558d263073ed95e46f4650becff0c5e1ffe0fc3a015de3c79283dfbdb3df"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4aa1d8707812a658debf03824016bf5ea0d516afdea29b7dc14cf687bc4d4ec6"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:76f27a809cda87e07f192f001d11adc2b930e93a2b0c4a236fde5429527423be"}, + {file = "pandas-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:1ba21b1d5c0e43416218db63037dbe1a01fc101dc6e6024bcad08123e48004ab"}, + {file = "pandas-2.2.1.tar.gz", hash = "sha256:0ab90f87093c13f3e8fa45b48ba9f39181046e8f3317d3aadb2fffbb1b978572"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + [[package]] name = "pathspec" version = "0.12.1" @@ -1996,79 +2471,80 @@ files = [ [[package]] name = "pillow" -version = "10.2.0" +version = "10.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, - {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, - {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, - {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, - {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, - {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, - {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, - {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, - {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, - {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, - {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, - {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, - {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, - {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, - {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, - {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, - {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, - {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] @@ -2202,30 +2678,78 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "pyarrow" +version = "15.0.2" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyarrow-15.0.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:88b340f0a1d05b5ccc3d2d986279045655b1fe8e41aba6ca44ea28da0d1455d8"}, + {file = "pyarrow-15.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eaa8f96cecf32da508e6c7f69bb8401f03745c050c1dd42ec2596f2e98deecac"}, + {file = "pyarrow-15.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23c6753ed4f6adb8461e7c383e418391b8d8453c5d67e17f416c3a5d5709afbd"}, + {file = "pyarrow-15.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f639c059035011db8c0497e541a8a45d98a58dbe34dc8fadd0ef128f2cee46e5"}, + {file = "pyarrow-15.0.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:290e36a59a0993e9a5224ed2fb3e53375770f07379a0ea03ee2fce2e6d30b423"}, + {file = "pyarrow-15.0.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:06c2bb2a98bc792f040bef31ad3e9be6a63d0cb39189227c08a7d955db96816e"}, + {file = "pyarrow-15.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:f7a197f3670606a960ddc12adbe8075cea5f707ad7bf0dffa09637fdbb89f76c"}, + {file = "pyarrow-15.0.2-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:5f8bc839ea36b1f99984c78e06e7a06054693dc2af8920f6fb416b5bca9944e4"}, + {file = "pyarrow-15.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5e81dfb4e519baa6b4c80410421528c214427e77ca0ea9461eb4097c328fa33"}, + {file = "pyarrow-15.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a4f240852b302a7af4646c8bfe9950c4691a419847001178662a98915fd7ee7"}, + {file = "pyarrow-15.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e7d9cfb5a1e648e172428c7a42b744610956f3b70f524aa3a6c02a448ba853e"}, + {file = "pyarrow-15.0.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2d4f905209de70c0eb5b2de6763104d5a9a37430f137678edfb9a675bac9cd98"}, + {file = "pyarrow-15.0.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:90adb99e8ce5f36fbecbbc422e7dcbcbed07d985eed6062e459e23f9e71fd197"}, + {file = "pyarrow-15.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:b116e7fd7889294cbd24eb90cd9bdd3850be3738d61297855a71ac3b8124ee38"}, + {file = "pyarrow-15.0.2-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:25335e6f1f07fdaa026a61c758ee7d19ce824a866b27bba744348fa73bb5a440"}, + {file = "pyarrow-15.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:90f19e976d9c3d8e73c80be84ddbe2f830b6304e4c576349d9360e335cd627fc"}, + {file = "pyarrow-15.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a22366249bf5fd40ddacc4f03cd3160f2d7c247692945afb1899bab8a140ddfb"}, + {file = "pyarrow-15.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2a335198f886b07e4b5ea16d08ee06557e07db54a8400cc0d03c7f6a22f785f"}, + {file = "pyarrow-15.0.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e6d459c0c22f0b9c810a3917a1de3ee704b021a5fb8b3bacf968eece6df098f"}, + {file = "pyarrow-15.0.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:033b7cad32198754d93465dcfb71d0ba7cb7cd5c9afd7052cab7214676eec38b"}, + {file = "pyarrow-15.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:29850d050379d6e8b5a693098f4de7fd6a2bea4365bfd073d7c57c57b95041ee"}, + {file = "pyarrow-15.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:7167107d7fb6dcadb375b4b691b7e316f4368f39f6f45405a05535d7ad5e5058"}, + {file = "pyarrow-15.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e85241b44cc3d365ef950432a1b3bd44ac54626f37b2e3a0cc89c20e45dfd8bf"}, + {file = "pyarrow-15.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:248723e4ed3255fcd73edcecc209744d58a9ca852e4cf3d2577811b6d4b59818"}, + {file = "pyarrow-15.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ff3bdfe6f1b81ca5b73b70a8d482d37a766433823e0c21e22d1d7dde76ca33f"}, + {file = "pyarrow-15.0.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:f3d77463dee7e9f284ef42d341689b459a63ff2e75cee2b9302058d0d98fe142"}, + {file = "pyarrow-15.0.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:8c1faf2482fb89766e79745670cbca04e7018497d85be9242d5350cba21357e1"}, + {file = "pyarrow-15.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:28f3016958a8e45a1069303a4a4f6a7d4910643fc08adb1e2e4a7ff056272ad3"}, + {file = "pyarrow-15.0.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:89722cb64286ab3d4daf168386f6968c126057b8c7ec3ef96302e81d8cdb8ae4"}, + {file = "pyarrow-15.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd0ba387705044b3ac77b1b317165c0498299b08261d8122c96051024f953cd5"}, + {file = "pyarrow-15.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2459bf1f22b6a5cdcc27ebfd99307d5526b62d217b984b9f5c974651398832"}, + {file = "pyarrow-15.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58922e4bfece8b02abf7159f1f53a8f4d9f8e08f2d988109126c17c3bb261f22"}, + {file = "pyarrow-15.0.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:adccc81d3dc0478ea0b498807b39a8d41628fa9210729b2f718b78cb997c7c91"}, + {file = "pyarrow-15.0.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8bd2baa5fe531571847983f36a30ddbf65261ef23e496862ece83bdceb70420d"}, + {file = "pyarrow-15.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6669799a1d4ca9da9c7e06ef48368320f5856f36f9a4dd31a11839dda3f6cc8c"}, + {file = "pyarrow-15.0.2.tar.gz", hash = "sha256:9c9bc803cb3b7bfacc1e96ffbfd923601065d9d3f911179d81e72d99fd74a3d9"}, +] + +[package.dependencies] +numpy = ">=1.16.6,<2" + [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.0" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, + {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.4.6,<0.7.0" [[package]] name = "pycodestyle" @@ -2240,13 +2764,13 @@ files = [ [[package]] name = "pydantic" -version = "2.6.2" +version = "2.6.4" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, - {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, + {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, + {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, ] [package.dependencies] @@ -2376,13 +2900,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -2450,18 +2974,52 @@ testing = ["filelock"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] six = ">=1.5" +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -2474,6 +3032,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2481,8 +3040,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2499,6 +3066,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2506,11 +3074,26 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "querystring-parser" +version = "1.2.4" +description = "QueryString parser for Python/Django that correctly handles nested dictionaries" +optional = false +python-versions = "*" +files = [ + {file = "querystring_parser-1.2.4-py2.py3-none-any.whl", hash = "sha256:d2fa90765eaf0de96c8b087872991a10238e89ba015ae59fedfed6bd61c242a0"}, + {file = "querystring_parser-1.2.4.tar.gz", hash = "sha256:644fce1cffe0530453b43a83a38094dbe422ccba8c9b2f2a1c00280e14ca8a62"}, +] + +[package.dependencies] +six = "*" + [[package]] name = "requests" version = "2.31.0" @@ -2534,13 +3117,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-oauthlib" -version = "1.3.1" +version = "2.0.0" description = "OAuthlib authentication support for Requests." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.4" files = [ - {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, - {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, ] [package.dependencies] @@ -2582,62 +3165,104 @@ files = [ [package.dependencies] pyasn1 = ">=0.1.3" +[[package]] +name = "scikit-learn" +version = "1.4.1.post1" +description = "A set of python modules for machine learning and data mining" +optional = false +python-versions = ">=3.9" +files = [ + {file = "scikit-learn-1.4.1.post1.tar.gz", hash = "sha256:93d3d496ff1965470f9977d05e5ec3376fb1e63b10e4fda5e39d23c2d8969a30"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c540aaf44729ab5cd4bd5e394f2b375e65ceaea9cdd8c195788e70433d91bbc5"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4310bff71aa98b45b46cd26fa641309deb73a5d1c0461d181587ad4f30ea3c36"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f43dd527dabff5521af2786a2f8de5ba381e182ec7292663508901cf6ceaf6e"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c02e27d65b0c7dc32f2c5eb601aaf5530b7a02bfbe92438188624524878336f2"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:629e09f772ad42f657ca60a1a52342eef786218dd20cf1369a3b8d085e55ef8f"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6145dfd9605b0b50ae72cdf72b61a2acd87501369a763b0d73d004710ebb76b5"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1afed6951bc9d2053c6ee9a518a466cbc9b07c6a3f9d43bfe734192b6125d508"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce03506ccf5f96b7e9030fea7eb148999b254c44c10182ac55857bc9b5d4815f"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ba516fcdc73d60e7f48cbb0bccb9acbdb21807de3651531208aac73c758e3ab"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:78cd27b4669513b50db4f683ef41ea35b5dddc797bd2bbd990d49897fd1c8a46"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a1e289f33f613cefe6707dead50db31930530dc386b6ccff176c786335a7b01c"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0df87de9ce1c0140f2818beef310fb2e2afdc1e66fc9ad587965577f17733649"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712c1c69c45b58ef21635360b3d0a680ff7d83ac95b6f9b82cf9294070cda710"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1754b0c2409d6ed5a3380512d0adcf182a01363c669033a2b55cca429ed86a81"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:1d491ef66e37f4e812db7e6c8286520c2c3fc61b34bf5e59b67b4ce528de93af"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aa0029b78ef59af22cfbd833e8ace8526e4df90212db7ceccbea582ebb5d6794"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:14e4c88436ac96bf69eb6d746ac76a574c314a23c6961b7d344b38877f20fee1"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cd3a77c32879311f2aa93466d3c288c955ef71d191503cf0677c3340ae8ae0"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a3ee19211ded1a52ee37b0a7b373a8bfc66f95353af058a210b692bd4cda0dd"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:234b6bda70fdcae9e4abbbe028582ce99c280458665a155eed0b820599377d25"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.19.5,<2.0" +scipy = ">=1.6.0" +threadpoolctl = ">=2.0.0" + +[package.extras] +benchmark = ["matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "pandas (>=1.1.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.19.12)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.17.2)"] + [[package]] name = "scipy" -version = "1.12.0" +version = "1.13.0" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, - {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, - {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, - {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, - {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, - {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, - {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, - {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, - {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, - {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, - {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, -] - -[package.dependencies] -numpy = ">=1.22.4,<1.29.0" - -[package.extras] -dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"}, + {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"}, + {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"}, + {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"}, + {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"}, + {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"}, + {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"}, + {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"}, + {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"}, + {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"}, + {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"}, + {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"}, + {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"}, + {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"}, + {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"}, + {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"}, + {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"}, + {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"}, + {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"}, + {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"}, + {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"}, + {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"}, + {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"}, + {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"}, + {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "setuptools" -version = "69.1.1" +version = "69.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, - {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, + {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, + {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -2662,6 +3287,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + [[package]] name = "snowballstemmer" version = "2.2.0" @@ -2899,6 +3535,109 @@ lint = ["docutils-stubs", "flake8", "mypy"] standalone = ["Sphinx (>=5)"] test = ["pytest"] +[[package]] +name = "sqlalchemy" +version = "2.0.29" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.29-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c142852ae192e9fe5aad5c350ea6befe9db14370b34047e1f0f7cf99e63c63b"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:99a1e69d4e26f71e750e9ad6fdc8614fbddb67cfe2173a3628a2566034e223c7"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ef3fbccb4058355053c51b82fd3501a6e13dd808c8d8cd2561e610c5456013c"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d6753305936eddc8ed190e006b7bb33a8f50b9854823485eed3a886857ab8d1"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0f3ca96af060a5250a8ad5a63699180bc780c2edf8abf96c58af175921df847a"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4520047006b1d3f0d89e0532978c0688219857eb2fee7c48052560ae76aca1e"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-win32.whl", hash = "sha256:b2a0e3cf0caac2085ff172c3faacd1e00c376e6884b5bc4dd5b6b84623e29e4f"}, + {file = "SQLAlchemy-2.0.29-cp310-cp310-win_amd64.whl", hash = "sha256:01d10638a37460616708062a40c7b55f73e4d35eaa146781c683e0fa7f6c43fb"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:308ef9cb41d099099fffc9d35781638986870b29f744382904bf9c7dadd08513"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:296195df68326a48385e7a96e877bc19aa210e485fa381c5246bc0234c36c78e"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a13b917b4ffe5a0a31b83d051d60477819ddf18276852ea68037a144a506efb9"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f6d971255d9ddbd3189e2e79d743ff4845c07f0633adfd1de3f63d930dbe673"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61405ea2d563407d316c63a7b5271ae5d274a2a9fbcd01b0aa5503635699fa1e"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de7202ffe4d4a8c1e3cde1c03e01c1a3772c92858837e8f3879b497158e4cb44"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-win32.whl", hash = "sha256:b5d7ed79df55a731749ce65ec20d666d82b185fa4898430b17cb90c892741520"}, + {file = "SQLAlchemy-2.0.29-cp311-cp311-win_amd64.whl", hash = "sha256:205f5a2b39d7c380cbc3b5dcc8f2762fb5bcb716838e2d26ccbc54330775b003"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d96710d834a6fb31e21381c6d7b76ec729bd08c75a25a5184b1089141356171f"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:52de4736404e53c5c6a91ef2698c01e52333988ebdc218f14c833237a0804f1b"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c7b02525ede2a164c5fa5014915ba3591730f2cc831f5be9ff3b7fd3e30958e"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dfefdb3e54cd15f5d56fd5ae32f1da2d95d78319c1f6dfb9bcd0eb15d603d5d"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a88913000da9205b13f6f195f0813b6ffd8a0c0c2bd58d499e00a30eb508870c"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fecd5089c4be1bcc37c35e9aa678938d2888845a134dd016de457b942cf5a758"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-win32.whl", hash = "sha256:8197d6f7a3d2b468861ebb4c9f998b9df9e358d6e1cf9c2a01061cb9b6cf4e41"}, + {file = "SQLAlchemy-2.0.29-cp312-cp312-win_amd64.whl", hash = "sha256:9b19836ccca0d321e237560e475fd99c3d8655d03da80c845c4da20dda31b6e1"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87a1d53a5382cdbbf4b7619f107cc862c1b0a4feb29000922db72e5a66a5ffc0"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a0732dffe32333211801b28339d2a0babc1971bc90a983e3035e7b0d6f06b93"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90453597a753322d6aa770c5935887ab1fc49cc4c4fdd436901308383d698b4b"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ea311d4ee9a8fa67f139c088ae9f905fcf0277d6cd75c310a21a88bf85e130f5"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5f20cb0a63a3e0ec4e169aa8890e32b949c8145983afa13a708bc4b0a1f30e03"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-win32.whl", hash = "sha256:e5bbe55e8552019c6463709b39634a5fc55e080d0827e2a3a11e18eb73f5cdbd"}, + {file = "SQLAlchemy-2.0.29-cp37-cp37m-win_amd64.whl", hash = "sha256:c2f9c762a2735600654c654bf48dad388b888f8ce387b095806480e6e4ff6907"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e614d7a25a43a9f54fcce4675c12761b248547f3d41b195e8010ca7297c369c"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:471fcb39c6adf37f820350c28aac4a7df9d3940c6548b624a642852e727ea586"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:988569c8732f54ad3234cf9c561364221a9e943b78dc7a4aaf35ccc2265f1930"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dddaae9b81c88083e6437de95c41e86823d150f4ee94bf24e158a4526cbead01"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:334184d1ab8f4c87f9652b048af3f7abea1c809dfe526fb0435348a6fef3d380"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:38b624e5cf02a69b113c8047cf7f66b5dfe4a2ca07ff8b8716da4f1b3ae81567"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-win32.whl", hash = "sha256:bab41acf151cd68bc2b466deae5deeb9e8ae9c50ad113444151ad965d5bf685b"}, + {file = "SQLAlchemy-2.0.29-cp38-cp38-win_amd64.whl", hash = "sha256:52c8011088305476691b8750c60e03b87910a123cfd9ad48576d6414b6ec2a1d"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3071ad498896907a5ef756206b9dc750f8e57352113c19272bdfdc429c7bd7de"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dba622396a3170974f81bad49aacebd243455ec3cc70615aeaef9e9613b5bca5"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b184e3de58009cc0bf32e20f137f1ec75a32470f5fede06c58f6c355ed42a72"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c37f1050feb91f3d6c32f864d8e114ff5545a4a7afe56778d76a9aec62638ba"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bda7ce59b06d0f09afe22c56714c65c957b1068dee3d5e74d743edec7daba552"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:25664e18bef6dc45015b08f99c63952a53a0a61f61f2e48a9e70cec27e55f699"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-win32.whl", hash = "sha256:77d29cb6c34b14af8a484e831ab530c0f7188f8efed1c6a833a2c674bf3c26ec"}, + {file = "SQLAlchemy-2.0.29-cp39-cp39-win_amd64.whl", hash = "sha256:04c487305ab035a9548f573763915189fc0fe0824d9ba28433196f8436f1449c"}, + {file = "SQLAlchemy-2.0.29-py3-none-any.whl", hash = "sha256:dc4ee2d4ee43251905f88637d5281a8d52e916a021384ec10758826f5cbae305"}, + {file = "SQLAlchemy-2.0.29.tar.gz", hash = "sha256:bd9566b8e58cabd700bc367b60e90d9349cd16f0984973f98a9a09f9c64e86f0"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + [[package]] name = "tensorboard" version = "2.15.2" @@ -2937,26 +3676,26 @@ files = [ [[package]] name = "tensorflow" -version = "2.15.0" +version = "2.15.1" description = "TensorFlow is an open source machine learning framework for everyone." optional = false python-versions = ">=3.9" files = [ - {file = "tensorflow-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:9b248e0f4316b3a3c54cd1f83edfb7a761d473060c1972a8ea31a90d5de3aa72"}, - {file = "tensorflow-2.15.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:eaf420d8b8ec1d4bd75859be7d7545d8e7052726eed8456fdbba63718e7e07ea"}, - {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98aab454fc73ff1900314821e5bafbf20840ada2004c8caccf4d92e0e12a628"}, - {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed601b43df9b7d9bed0203b34bcb9356efd4f671eaaac1046b7166a2afee0cf8"}, - {file = "tensorflow-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:2d88f8b71f4a8d9ab9dc7c8e42b14ca0f53d1daab0f989b8f2918907c2891f41"}, - {file = "tensorflow-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1e0716622ed7af867d8b1997b00a2940f1a1587dee923ff53efa2ee506992f32"}, - {file = "tensorflow-2.15.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:124930e7d4f5d74c61a5c80d642a26c22fe0c42fdd383fe9ee5803c3ac9ed4ce"}, - {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852efeb4d18beedac0120c4f2d4f4dccf4c090bb6740c5199d395ff609e85e98"}, - {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee8ec2b2c6c942ae65d25746e53cdc475e82d5fcbbb3009ce47f5963d69ebfc"}, - {file = "tensorflow-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:e05a48006930e4e9e68468e7affed3bbce8a1c7fe6df86500496ad1558804a78"}, - {file = "tensorflow-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2cfcdde1ff3c01be617e99ce9783c49cb11da5796ce32a31855412bd092c0bcf"}, - {file = "tensorflow-2.15.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:896bda03f722700a9918d144aee5152a75f1be5e6c5045fd0683b8318a3fc9d9"}, - {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7697b005ce48fec8b2ee8cf25bcbd138f16b5e17f99f7c01a6ea3f2429f86c6"}, - {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa865956d96b7614f247c36e4c22b1543ba5ce656fbe8e4f6266ae7a4917132"}, - {file = "tensorflow-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:01108746e1bbfcd48dfabf7f51ddca7693b91ea6821f6f62a27b5a5ebf0817c5"}, + {file = "tensorflow-2.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:91b51a507007d63a70b65be307d701088d15042a6399c0e2312b53072226e909"}, + {file = "tensorflow-2.15.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:10132acc072d59696c71ce7221d2d8e0e3ff1e6bc8688dbac6d7aed8e675b710"}, + {file = "tensorflow-2.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c5ef9c758ec9ff7ce2aff76b71c980bc5119b879071c2cc623b1591a497a1a"}, + {file = "tensorflow-2.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea290e435464cf0794f657b48786e5fa413362abe55ed771c172c25980d070ce"}, + {file = "tensorflow-2.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:8e5431d45ceb416c2b1b6de87378054fbac7d2ed35d45b102d89a786613fffdc"}, + {file = "tensorflow-2.15.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:6761efe511e6ee0f893f60738fefbcc51d6dc386eeaaafea59d21899ef369ffd"}, + {file = "tensorflow-2.15.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:aa926114d1e13ffe5b2ea59c3f195216f26646d7fe36e9e5207b291e4b7902ff"}, + {file = "tensorflow-2.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e73d43dbc68d8c711e70edecc4ac70472799a25ec4ec18a84d479ee18033d3c5"}, + {file = "tensorflow-2.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb0edd69103c154245c5f209f0507355cc68ba7e4de350084bc31edc562478e4"}, + {file = "tensorflow-2.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:a49f8755c74a89553294a99ab25aa87ab1cddbfa40fe58387e09f64f0578cedc"}, + {file = "tensorflow-2.15.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f8e85821317c9c0fbf1256e9f721cfb1400ba1e09becb844b3ddd91f744805fc"}, + {file = "tensorflow-2.15.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:b75815b6a601edad52b4181e9805c8fcd04813a6ab1d5cd8127188dfd2788e20"}, + {file = "tensorflow-2.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:432788ac5d1234b9e9b7c7f73603a5655271a28c293329c52c7c0b9434a1184e"}, + {file = "tensorflow-2.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89b5aa1022dec47e567512eaf4e1271b8e6c1ff1984e30d0d9127bd1093ed4c5"}, + {file = "tensorflow-2.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:aaf3cfa290597ebbdf19d1a78729e3f555e459506cd58f8d7399359ac5e02a05"}, ] [package.dependencies] @@ -2969,7 +3708,7 @@ grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -ml-dtypes = ">=0.2.0,<0.3.0" +ml-dtypes = ">=0.3.1,<0.4.0" numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" @@ -2977,31 +3716,33 @@ protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4 setuptools = "*" six = ">=1.12.0" tensorboard = ">=2.15,<2.16" +tensorflow-cpu-aws = {version = "2.15.1", markers = "platform_system == \"Linux\" and (platform_machine == \"arm64\" or platform_machine == \"aarch64\")"} tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-intel = {version = "2.15.1", markers = "platform_system == \"Windows\""} tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" [package.extras] -and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)"] [[package]] name = "tensorflow-cpu" -version = "2.15.0" +version = "2.15.1" description = "TensorFlow is an open source machine learning framework for everyone." optional = false python-versions = ">=3.9" files = [ - {file = "tensorflow_cpu-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:67bac86d3fce227e59fdd31d1ac45e25cfa2f2c0a3a1269b1d2acf5721fcb7af"}, - {file = "tensorflow_cpu-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f60b3d4270a507eef10d9da5ab55fdec90a4c77c664dde446709b597f0864a62"}, - {file = "tensorflow_cpu-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc52cdceb0f2e5853599e9226987ba8f260347b5b1591c8efb60b13ba2ea9fa8"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:b0b2986a6cf63053c1f63bc751b228f5478283c0aa66a58271e931ae318978ce"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46c795177f6311c83562e05d38dc7d4618f8d3150e6902a4499b875f3f97270"}, - {file = "tensorflow_cpu-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:4487d0991e6f71bb56000f49a8ba467786b1ed7fafc7a6c0fad6d10ea46fc304"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f02026dbb9c2d953d27d2c44de65ecf5e42f002750ae560b63484e50f869a16f"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfd3bdc43e29a9239d05f4c116c2fb7c38dd388222d3c934138dfbcb93e5a506"}, - {file = "tensorflow_cpu-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:6900344496f0defd54c5da4aa2228bf0f332fb0a6cb5136b90b3541a6e4322d6"}, + {file = "tensorflow_cpu-2.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f211b011e812f827f5452b1d5f19865645c65df6e2a07d71118480c40887133e"}, + {file = "tensorflow_cpu-2.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9503db2c5357ea21938555323581fbdabf3d051b6bc1b5f73c5b0ae034d077"}, + {file = "tensorflow_cpu-2.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:dcf2d31c59abddfe6f1a86ca3e4dee99428c59831b1939a984622e0b19b52fcf"}, + {file = "tensorflow_cpu-2.15.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:ee3bb114c6031d471d891c761e7eda2c80bea19bb318abcd3d5bab92ccfaf9aa"}, + {file = "tensorflow_cpu-2.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54660c074d7241a503e81edfd9f5ef5af88f64051b72e2945f26318c790f2d26"}, + {file = "tensorflow_cpu-2.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc75baf4c08a6e8ab7ceec97f002bb993508a5b58f13fac5283ee976a71a3c67"}, + {file = "tensorflow_cpu-2.15.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:481f3f38fac552f0915052292614c57875e44ff7e235edc11fa847e313c09c83"}, + {file = "tensorflow_cpu-2.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:102b27b17e5f6023886b0cb07835af56cd135b845c1b92e597018ba77e54e480"}, + {file = "tensorflow_cpu-2.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:951d78693b61239464bee5ae9c20b6c845d82ae0a2092ee5abebb96b5e2db02e"}, ] [package.dependencies] @@ -3014,7 +3755,7 @@ grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -ml-dtypes = ">=0.2.0,<0.3.0" +ml-dtypes = ">=0.3.1,<0.4.0" numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" @@ -3022,14 +3763,55 @@ protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4 setuptools = "*" six = ">=1.12.0" tensorboard = ">=2.15,<2.16" +tensorflow-cpu-aws = {version = "2.15.1", markers = "platform_system == \"Linux\" and (platform_machine == \"arm64\" or platform_machine == \"aarch64\")"} tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-intel = {version = "2.15.1", markers = "platform_system == \"Windows\""} tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" [package.extras] -and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)"] + +[[package]] +name = "tensorflow-cpu-aws" +version = "2.15.1" +description = "TensorFlow is an open source machine learning framework for everyone." +optional = false +python-versions = ">=3.9" +files = [ + {file = "tensorflow_cpu_aws-2.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c781d95cb8c58d47cb012b7b4e77b2f3e8d4d47b45926bc54976506fa0c037cc"}, + {file = "tensorflow_cpu_aws-2.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4c3a3a9363bf42999adedbbd514e3a133be2d62f61fee9cfa46aaefb087c09e"}, + {file = "tensorflow_cpu_aws-2.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9a25f2b9da4740074fdd89bd2a4cf280a9d40b1d26a973ef079e6673c1bf7de"}, +] + +[package.dependencies] +absl-py = ">=1.0.0" +astunparse = ">=1.6.0" +flatbuffers = ">=23.5.26" +gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" +google-pasta = ">=0.1.1" +grpcio = ">=1.24.3,<2.0" +h5py = ">=2.9.0" +keras = ">=2.15.0,<2.16" +libclang = ">=13.0.0" +ml-dtypes = ">=0.3.1,<0.4.0" +numpy = ">=1.23.5,<2.0.0" +opt-einsum = ">=2.3.2" +packaging = "*" +protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +setuptools = "*" +six = ">=1.12.0" +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-io-gcs-filesystem = ">=0.23.1" +termcolor = ">=1.1.0" +typing-extensions = ">=3.6.6" +wrapt = ">=1.11.0,<1.15" + +[package.extras] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)"] [[package]] name = "tensorflow-datasets" @@ -3107,6 +3889,45 @@ files = [ {file = "tensorflow_estimator-2.15.0-py2.py3-none-any.whl", hash = "sha256:aedf21eec7fb2dc91150fc91a1ce12bc44dbb72278a08b58e79ff87c9e28f153"}, ] +[[package]] +name = "tensorflow-intel" +version = "2.15.1" +description = "TensorFlow is an open source machine learning framework for everyone." +optional = false +python-versions = ">=3.9" +files = [ + {file = "tensorflow_intel-2.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f305142b3c5e239c82c463429b1f88726dd27d9f23523871f825493a9ffc5f4"}, + {file = "tensorflow_intel-2.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:4f05059493f8203285ac5cea3b1955887a7903c1ca6f7a29e4b6ef912b1f934b"}, + {file = "tensorflow_intel-2.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:921f18f7eb9cf59769e9668b3935fe178c990e2973d8013870dae5e3b58de079"}, +] + +[package.dependencies] +absl-py = ">=1.0.0" +astunparse = ">=1.6.0" +flatbuffers = ">=23.5.26" +gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" +google-pasta = ">=0.1.1" +grpcio = ">=1.24.3,<2.0" +h5py = ">=2.9.0" +keras = ">=2.15.0,<2.16" +libclang = ">=13.0.0" +ml-dtypes = ">=0.3.1,<0.4.0" +numpy = ">=1.23.5,<2.0.0" +opt-einsum = ">=2.3.2" +packaging = "*" +protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +setuptools = "*" +six = ">=1.12.0" +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" +tensorflow-io-gcs-filesystem = ">=0.23.1" +termcolor = ">=1.1.0" +typing-extensions = ">=3.6.6" +wrapt = ">=1.11.0,<1.15" + +[package.extras] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)"] + [[package]] name = "tensorflow-io-gcs-filesystem" version = "0.36.0" @@ -3153,31 +3974,32 @@ protobuf = ">=3.20.3,<4.21" [[package]] name = "tensorstore" -version = "0.1.45" +version = "0.1.56" description = "Read and write large, multi-dimensional arrays" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "tensorstore-0.1.45-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:2ff6e5177ba2702f348bef3edc37619aa7646e43f33d1a567ba267db455699e4"}, - {file = "tensorstore-0.1.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bc7cde6318363eb9d35fc6cacb6fcd5d7a03b0ee57bdd69249108c0164692d8"}, - {file = "tensorstore-0.1.45-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405bf40271eed5632a566cdb935beba87d9896d2f80caf75386febb529ddba45"}, - {file = "tensorstore-0.1.45-cp310-cp310-win_amd64.whl", hash = "sha256:537805adb06fff2ce9a259b81920af4c34a20f752fa28205e722b7e58a60c790"}, - {file = "tensorstore-0.1.45-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:73df4ddafe4da8e0f919ed5a75f48839013da3a99128a719fe730855252051a6"}, - {file = "tensorstore-0.1.45-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f38bba6fc0668a950b76752c743b66851c4fc7360857e8b37a4f7a4e9786760b"}, - {file = "tensorstore-0.1.45-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca212d127fcc4debb9f6b4274d584fe7724b2a349ca9444258a4127878dc3033"}, - {file = "tensorstore-0.1.45-cp311-cp311-win_amd64.whl", hash = "sha256:a8960f0e546ee493ed67b77998859f0cb94772ea31e865bf76b0c79976ac9204"}, - {file = "tensorstore-0.1.45-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:871a1fde0712a153ac44774ddace3ad841609ff5be792734d44cffb520258e92"}, - {file = "tensorstore-0.1.45-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0ce1a3d2bdbdb2c1102100ee23fa99a95b0bcdee9773862622d7da833516c8c9"}, - {file = "tensorstore-0.1.45-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8659688ec9d89cdd71046c35b3c84cf92cd8c88251e6068f8a99d6991a965028"}, - {file = "tensorstore-0.1.45-cp38-cp38-win_amd64.whl", hash = "sha256:c034fec18b6e3174d26df1cdd91ec67b720fc5de7ef0cc3804017dad8c211622"}, - {file = "tensorstore-0.1.45-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4915aee8355ee7dbc6f534d77a28c18001e19696f44f78760ec42845ac51edee"}, - {file = "tensorstore-0.1.45-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4346ab7afa0963dcaa8e64388a2bedab741c790786b577326a0b174d226c9320"}, - {file = "tensorstore-0.1.45-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05196a0464ce51867f1edd96e992fe01281de283b034d434ca6e81db319368c0"}, - {file = "tensorstore-0.1.45-cp39-cp39-win_amd64.whl", hash = "sha256:6d7b6cccb96b36356d3e61c4e89972b82123d799cc2ca50f743e30ce45d70739"}, - {file = "tensorstore-0.1.45.tar.gz", hash = "sha256:38468c621b2edf09cfdd2df4905890e83f1805c7645ec13e16df5eafabf0e5e5"}, + {file = "tensorstore-0.1.56-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:3293a33be31cafcc2feaf50b7551ea82d9d69a298b82e101f63f85569b642692"}, + {file = "tensorstore-0.1.56-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d0007989093e2bde4fc5def98726e4aff2d6513f1edb4232bf5af8993c9fff5"}, + {file = "tensorstore-0.1.56-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b320e36fcbf59337a270ab15e3791ca3a2720783a53491f27ff9e9477d04cbc"}, + {file = "tensorstore-0.1.56-cp310-cp310-win_amd64.whl", hash = "sha256:3b6f1a318f94f87e0808e9c34b5399e0819e202788287ba364896b225465f32f"}, + {file = "tensorstore-0.1.56-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:561daafc8a4c9939fa4899d53a6b6b7472c0c25b3614b51e7b44cbd9c4f2d375"}, + {file = "tensorstore-0.1.56-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5cb6dd6a6528a498b537b55c70bc4a65a302ed3a223f1b76199f840edd1b34e1"}, + {file = "tensorstore-0.1.56-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ff3a6bbc2ce2a48295bcc7227e2fcd466bb2d3237852f40ccd9f48555159c23"}, + {file = "tensorstore-0.1.56-cp311-cp311-win_amd64.whl", hash = "sha256:47a04620b674cb9661a4fa4c6b147b4b29c44da16c00007e5051a01717e4b1bc"}, + {file = "tensorstore-0.1.56-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:e663eb20d5156a09a1075430e878cf0b85dbf12cf3e5072f527ebf56412c3abd"}, + {file = "tensorstore-0.1.56-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:417f0b09605c5e3f1e1a79d575cf81e2d191bff0caa590b4f2e6e7dcba981f70"}, + {file = "tensorstore-0.1.56-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:403b24aef3a9d760b3a387315e8815d1fa57a814085928a201fe39e5080716f6"}, + {file = "tensorstore-0.1.56-cp312-cp312-win_amd64.whl", hash = "sha256:bd455a3299a8764ecddb00717f3231b396e41b7f1262a4d01443016361eaeb04"}, + {file = "tensorstore-0.1.56-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4c3dbf8c239c48ff18d0ff62d364e78138eb49e16c41f40bcad8a1446412448d"}, + {file = "tensorstore-0.1.56-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:80725708276d321f59b7d4a4d4fd3d9e6ba111d89b232269d8f3e6ece3d3e340"}, + {file = "tensorstore-0.1.56-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e1dc7b9b82975b2d41fe43258ff5a58eecc9d73a596b19a08ecb43b278cf6ba"}, + {file = "tensorstore-0.1.56-cp39-cp39-win_amd64.whl", hash = "sha256:abb853ee019ac41e11123ae92f0c76bcb27135ba7910fc8b62b120c6668ef11a"}, + {file = "tensorstore-0.1.56.tar.gz", hash = "sha256:5f8f7bc056cb15bc0d45fedfe1ec38029d6f361aa2fb155a218a577a6d953013"}, ] [package.dependencies] +ml-dtypes = ">=0.3.1" numpy = ">=1.16.0" [[package]] @@ -3194,6 +4016,17 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] +[[package]] +name = "threadpoolctl" +version = "3.4.0" +description = "threadpoolctl" +optional = false +python-versions = ">=3.8" +files = [ + {file = "threadpoolctl-3.4.0-py3-none-any.whl", hash = "sha256:8f4c689a65b23e5ed825c8436a92b818aac005e0f3715f6a1664d7c7ee29d262"}, + {file = "threadpoolctl-3.4.0.tar.gz", hash = "sha256:f11b491a03661d6dd7ef692dd422ab34185d982466c49c8f98c8f716b5c93196"}, +] + [[package]] name = "toml" version = "0.10.2" @@ -3296,6 +4129,17 @@ files = [ {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + [[package]] name = "urllib3" version = "2.2.1" @@ -3333,15 +4177,30 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "waitress" +version = "3.0.0" +description = "Waitress WSGI server" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"}, + {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, +] + +[package.extras] +docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] +testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] + [[package]] name = "werkzeug" -version = "3.0.1" +version = "3.0.2" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, - {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, + {file = "werkzeug-3.0.2-py3-none-any.whl", hash = "sha256:3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795"}, + {file = "werkzeug-3.0.2.tar.gz", hash = "sha256:e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d"}, ] [package.dependencies] @@ -3352,13 +4211,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.42.0" +version = "0.43.0" description = "A built-package format for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "wheel-0.42.0-py3-none-any.whl", hash = "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"}, - {file = "wheel-0.42.0.tar.gz", hash = "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8"}, + {file = "wheel-0.43.0-py3-none-any.whl", hash = "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"}, + {file = "wheel-0.43.0.tar.gz", hash = "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85"}, ] [package.extras] @@ -3390,6 +4249,16 @@ files = [ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecee4132c6cd2ce5308e21672015ddfed1ff975ad0ac8d27168ea82e71413f55"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2020f391008ef874c6d9e208b24f28e31bcb85ccff4f335f15a3251d222b92d9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2feecf86e1f7a86517cab34ae6c2f081fd2d0dac860cb0c0ded96d799d20b335"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:240b1686f38ae665d1b15475966fe0472f78e71b1b4903c143a842659c8e4cb9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9008dad07d71f68487c91e96579c8567c98ca4c3881b9b113bc7b33e9fd78b8"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6447e9f3ba72f8e2b985a1da758767698efa72723d5b59accefd716e9e8272bf"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acae32e13a4153809db37405f5eba5bac5fbe2e2ba61ab227926a22901051c0a"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49ef582b7a1152ae2766557f0550a9fcbf7bbd76f43fbdc94dd3bf07cc7168be"}, + {file = "wrapt-1.14.1-cp311-cp311-win32.whl", hash = "sha256:358fe87cc899c6bb0ddc185bf3dbfa4ba646f05b1b0b9b5a27c2cb92c2cea204"}, + {file = "wrapt-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:26046cd03936ae745a502abf44dac702a5e6880b2b01c29aea8ddf3353b68224"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, @@ -3439,18 +4308,18 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "znh5md" @@ -3476,4 +4345,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "644ac71059a5fb1c264908c3d41b1c05575697f1e3d13d0e8bec33b419db4ad0" +content-hash = "ed000b93e5253f86c46aa7708c3e7483d76713473d2e460efa1d11f501901298" diff --git a/pyproject.toml b/pyproject.toml index d62d4677..c34d5ddc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,10 @@ sphinx-copybutton = "^0.5.2" sphinx-autodoc-typehints = "^1.25.2" furo = "^2023.9.10" + +[tool.poetry.group.extras.dependencies] +mlflow = "^2.11.3" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From 9394fc95746ed0fa29695e04e452e49282b89c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 3 Apr 2024 18:04:32 +0200 Subject: [PATCH 132/192] added support for MLFlow Callback --- apax/config/common.py | 14 ++++++++++ apax/config/train_config.py | 41 ++++++++++++++++++++++++----- apax/train/callbacks.py | 52 +++++++++++++++++++++++-------------- apax/train/run.py | 2 +- apax/train/trainer.py | 10 ++++--- 5 files changed, 89 insertions(+), 30 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index 843830bb..c2acaf5a 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -1,5 +1,6 @@ import logging import os +from collections.abc import MutableMapping from typing import Union import yaml @@ -28,3 +29,16 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> config = MDConfig.model_validate(config) return config + + +def flatten(dictionary, parent_key="", separator="_"): + """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys + """ + items = [] + for key, value in dictionary.items(): + new_key = parent_key + separator + key if parent_key else key + if isinstance(value, MutableMapping): + items.extend(flatten(value, new_key, separator=separator).items()) + else: + items.append((new_key, value)) + return dict(items) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 3cd5f57c..1a266d1d 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -1,12 +1,13 @@ import logging import os from pathlib import Path -from typing import List, Literal, Optional +from typing import List, Literal, Optional, Union import yaml from pydantic import ( BaseModel, ConfigDict, + Field, NonNegativeFloat, PositiveFloat, PositiveInt, @@ -235,16 +236,42 @@ class LossConfig(BaseModel, extra="forbid"): parameters: dict = {} -class CallbackConfig(BaseModel, frozen=True, extra="forbid"): +class CSVCallback(BaseModel, frozen=True, extra="forbid"): """ - Configuration of the training callbacks. + Configuration of the CSVCallback. Parameters ---------- - name: Keyword of the callback used. Currently we implement "csv" and "tensorboard". + name: Keyword of the callback used.. """ - name: str + name: Literal["csv"] + + +class TBCallback(BaseModel, frozen=True, extra="forbid"): + """ + Configuration of the TensorBoard callback. + + Parameters + ---------- + name: Keyword of the callback used.. + """ + + name: Literal["tensorboard"] + + +class MLFlowCallback(BaseModel, frozen=True, extra="forbid"): + """ + Configuration of the MLFlow callback. + + Parameters + ---------- + name: Keyword of the callback used. + experiment: Path to the MLFlow experiment, e.g. /Users// + """ + + name: Literal["mlflow"] + experiment: str class TrainProgressbarConfig(BaseModel, extra="forbid"): @@ -311,7 +338,9 @@ class Config(BaseModel, frozen=True, extra="forbid"): metrics: List[MetricsConfig] = [] loss: List[LossConfig] optimizer: OptimizerConfig = OptimizerConfig() - callbacks: List[CallbackConfig] = [CallbackConfig(name="csv")] + callbacks: List[Union[CSVCallback, TBCallback, MLFlowCallback]] = Field( + CSVCallback(name="csv"), discriminator="name" + ) progress_bar: TrainProgressbarConfig = TrainProgressbarConfig() checkpoints: CheckpointConfig = CheckpointConfig() diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 460cad04..b5e654d0 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -1,12 +1,17 @@ import logging +from pathlib import Path import tensorflow as tf from keras.callbacks import CSVLogger, TensorBoard +from apax.config.common import flatten +from apax.config.train_config import Config + log = logging.getLogger(__name__) -def initialize_callbacks(callback_configs, model_version_path): +def initialize_callbacks(config: Config, model_version_path: Path): + callback_configs = config.callbacks log.info("Initializing Callbacks") dummy_model = tf.keras.Model() @@ -27,32 +32,41 @@ def initialize_callbacks(callback_configs, model_version_path): }, } - callback_configs = [config.name for config in callback_configs] - if "csv" in callback_configs and "tensorboard" in callback_configs: - csv_idx, tb_idx = callback_configs.index("csv"), callback_configs.index( - "tensorboard" - ) + names = [conf.name for conf in callback_configs] + if "csv" in names and "tensorboard" in names: msg = ( "Using both csv and tensorboard callbacks is not supported at the moment." - " Only the first of the two will be used." + " Rerun training with only one of the two." ) - print("Warning: " + msg) - log.warning(msg) - if csv_idx < tb_idx: - callback_configs.pop(tb_idx) - else: - callback_configs.pop(csv_idx) + raise ValueError(msg) callbacks = [] for callback_config in callback_configs: - callback_info = callback_dict[callback_config] + if callback_config.name == "mlflow": + try: + import mlflow + from mlflow.tensorflow import MLflowCallback + except ImportError: + log.warning("Make sure MLFlow is installed correctly") + mlflow.login() + mlflow.tensorflow.autolog() + experiment = callback_config.experiment + mlflow.set_experiment(experiment) + + params = config.model_dump() + params = flatten(params) + mlflow.log_params(params) + callback = MLflowCallback() + callback.set_model(dummy_model) + else: + callback_info = callback_dict[callback_config.name] - path_arg_name = callback_info["path_arg_name"] - path = {path_arg_name: callback_info["log_path"]} + path_arg_name = callback_info["path_arg_name"] + path = {path_arg_name: callback_info["log_path"]} - kwargs = callback_info["kwargs"] - callback = callback_info["class"](**path, **kwargs) - callback.set_model(callback_info["model"]) + kwargs = callback_info["kwargs"] + callback = callback_info["class"](**path, **kwargs) + callback.set_model(callback_info["model"]) callbacks.append(callback) return tf.keras.callbacks.CallbackList([callback]) diff --git a/apax/train/run.py b/apax/train/run.py index fe408ab6..b4f46a83 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -95,7 +95,7 @@ def run(user_config, log_level="error"): setup_logging(config.data.model_version_path / "train.log", log_level) config.dump_config(config.data.model_version_path) - callbacks = initialize_callbacks(config.callbacks, config.data.model_version_path) + callbacks = initialize_callbacks(config, config.data.model_version_path) loss_fn = initialize_loss_fn(config.loss) Metrics = initialize_metrics(config.metrics) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 8c040a3f..6d6bc0f0 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,10 +107,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From 0f8b3aa09e36451d77b5aa2656f8763dccbc2fa3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:10:41 +0000 Subject: [PATCH 133/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/config/common.py | 3 +-- apax/train/trainer.py | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index c2acaf5a..393dfdb4 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -32,8 +32,7 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> def flatten(dictionary, parent_key="", separator="_"): - """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys - """ + """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys""" items = [] for key, value in dictionary.items(): new_key = parent_key + separator + key if parent_key else key diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 6d6bc0f0..8c040a3f 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,12 +107,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 41eeea4c824151c8aa9ad97e2fe30316ffbc10c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:23:55 +0200 Subject: [PATCH 134/192] fixed config callback default --- apax/config/common.py | 3 ++- apax/config/train_config.py | 10 +++++++--- apax/train/callbacks.py | 1 - apax/train/trainer.py | 10 ++++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index 393dfdb4..c2acaf5a 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -32,7 +32,8 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> def flatten(dictionary, parent_key="", separator="_"): - """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys""" + """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys + """ items = [] for key, value in dictionary.items(): new_key = parent_key + separator + key if parent_key else key diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 1a266d1d..9edf383d 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -14,6 +14,7 @@ create_model, model_validator, ) +from typing_extensions import Annotated from apax.data.statistics import scale_method_list, shift_method_list @@ -274,6 +275,11 @@ class MLFlowCallback(BaseModel, frozen=True, extra="forbid"): experiment: str +CallBack = Annotated[ + Union[CSVCallback, TBCallback, MLFlowCallback], Field(discriminator="name") +] + + class TrainProgressbarConfig(BaseModel, extra="forbid"): """ Configuration of progressbars. @@ -338,9 +344,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): metrics: List[MetricsConfig] = [] loss: List[LossConfig] optimizer: OptimizerConfig = OptimizerConfig() - callbacks: List[Union[CSVCallback, TBCallback, MLFlowCallback]] = Field( - CSVCallback(name="csv"), discriminator="name" - ) + callbacks: List[CallBack] = [CSVCallback(name="csv")] progress_bar: TrainProgressbarConfig = TrainProgressbarConfig() checkpoints: CheckpointConfig = CheckpointConfig() diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index b5e654d0..5979a7d1 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -31,7 +31,6 @@ def initialize_callbacks(config: Config, model_version_path: Path): "model": dummy_model, }, } - names = [conf.name for conf in callback_configs] if "csv" in names and "tensorboard" in names: msg = ( diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 8c040a3f..6d6bc0f0 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,10 +107,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From 4f4b56e84a70dd2e2b05451a75f9ddca35c90d62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 07:24:05 +0000 Subject: [PATCH 135/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/config/common.py | 3 +-- apax/train/trainer.py | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index c2acaf5a..393dfdb4 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -32,8 +32,7 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> def flatten(dictionary, parent_key="", separator="_"): - """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys - """ + """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys""" items = [] for key, value in dictionary.items(): new_key = parent_key + separator + key if parent_key else key diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 6d6bc0f0..8c040a3f 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,12 +107,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 6fb6b251ce89bf33c4071cd073552aa85efe79a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:25:16 +0200 Subject: [PATCH 136/192] updated test config --- tests/regression_tests/apax_config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regression_tests/apax_config.yaml b/tests/regression_tests/apax_config.yaml index b112941e..1a78b714 100644 --- a/tests/regression_tests/apax_config.yaml +++ b/tests/regression_tests/apax_config.yaml @@ -50,10 +50,10 @@ metrics: # - mse loss: - - loss_type: structures + - loss_type: mse name: energy weight: 1.0 - - loss_type: structures + - loss_type: mse name: forces weight: 8.0 - loss_type: cosine_sim @@ -74,7 +74,7 @@ optimizer: transition_begin: 0 callbacks: -- name: csv + - name: csv checkpoints: ckpt_interval: 1 From 4ae677070c65def40328b889425335941713b926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:29:28 +0200 Subject: [PATCH 137/192] linting --- apax/config/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apax/config/common.py b/apax/config/common.py index 393dfdb4..cae30bda 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -32,7 +32,9 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> def flatten(dictionary, parent_key="", separator="_"): - """https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys""" + """https://stackoverflow.com/questions/6027558/ + flatten-nested-dictionaries-compressing-keys + """ items = [] for key, value in dictionary.items(): new_key = parent_key + separator + key if parent_key else key From 9ee9afa0b22a22938563a0e15b00b9105092b679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:54:49 +0200 Subject: [PATCH 138/192] removed use of deprecated nl pbar kw --- apax/cli/templates/train_config_full.yaml | 1 - tests/regression_tests/apax_config.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/apax/cli/templates/train_config_full.yaml b/apax/cli/templates/train_config_full.yaml index 0f330ef0..3a7d9d75 100644 --- a/apax/cli/templates/train_config_full.yaml +++ b/apax/cli/templates/train_config_full.yaml @@ -78,4 +78,3 @@ checkpoints: progress_bar: disable_epoch_pbar: false - disable_nl_pbar: false diff --git a/tests/regression_tests/apax_config.yaml b/tests/regression_tests/apax_config.yaml index b112941e..773ec9f3 100644 --- a/tests/regression_tests/apax_config.yaml +++ b/tests/regression_tests/apax_config.yaml @@ -84,4 +84,3 @@ checkpoints: progress_bar: disable_epoch_pbar: true - disable_nl_pbar: true From 5cf2faed796455ece449fec345d9f216d6beac28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:55:23 +0200 Subject: [PATCH 139/192] added batch pbar --- apax/config/train_config.py | 4 ++-- apax/train/run.py | 1 + apax/train/trainer.py | 33 +++++++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 3cd5f57c..51dcf0cc 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -254,11 +254,11 @@ class TrainProgressbarConfig(BaseModel, extra="forbid"): Parameters ---------- disable_epoch_pbar: Set to True to disable the epoch progress bar. - disable_nl_pbar: Set to True to disable the NL precomputation progress bar. + disable_batch_pbar: Set to True to disable the batch progress bar. """ disable_epoch_pbar: bool = False - disable_nl_pbar: bool = False + disable_batch_pbar: bool = True class CheckpointConfig(BaseModel, extra="forbid"): diff --git a/apax/train/run.py b/apax/train/run.py index fe408ab6..7ea9c949 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -144,5 +144,6 @@ def run(user_config, log_level="error"): sam_rho=config.optimizer.sam_rho, patience=config.patience, disable_pbar=config.progress_bar.disable_epoch_pbar, + disable_batch_pbar=config.progress_bar.disable_batch_pbar, is_ensemble=config.n_models > 1, ) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 8c040a3f..9f77864c 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -29,6 +29,7 @@ def fit( sam_rho=0.0, patience: Optional[int] = None, disable_pbar: bool = False, + disable_batch_pbar: bool = True, is_ensemble=False, ): log.info("Beginning Training") @@ -70,6 +71,16 @@ def fit( epoch_loss.update({"train_loss": 0.0}) train_batch_metrics = Metrics.empty() + batch_pbar = trange( + 0, + train_steps_per_epoch, + desc="Batches", + ncols=100, + mininterval=1.0, + disable=disable_batch_pbar, + leave=False, + ) + for batch_idx in range(train_steps_per_epoch): callbacks.on_train_batch_begin(batch=batch_idx) @@ -84,6 +95,7 @@ def fit( epoch_loss["train_loss"] += jnp.mean(batch_loss) callbacks.on_train_batch_end(batch=batch_idx) + batch_pbar.update() epoch_loss["train_loss"] /= train_steps_per_epoch epoch_loss["train_loss"] = float(epoch_loss["train_loss"]) @@ -96,6 +108,16 @@ def fit( if val_ds is not None: epoch_loss.update({"val_loss": 0.0}) val_batch_metrics = Metrics.empty() + + batch_pbar = trange( + 0, + val_steps_per_epoch, + desc="Batches", + ncols=100, + mininterval=1.0, + disable=disable_batch_pbar, + leave=False, + ) for batch_idx in range(val_steps_per_epoch): batch = next(batch_val_ds) @@ -103,14 +125,17 @@ def fit( state.params, batch, val_batch_metrics ) epoch_loss["val_loss"] += batch_loss + batch_pbar.update() epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From 3a81b71c8e9218744d9872bfd09d9fa7098f84e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:58:34 +0200 Subject: [PATCH 140/192] added log info on the devices in use --- apax/train/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/train/run.py b/apax/train/run.py index 7ea9c949..bc1bdf68 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -90,10 +90,10 @@ def run(user_config, log_level="error"): seed_py_np_tf(config.seed) rng_key = jax.random.PRNGKey(config.seed) - log.info("Initializing directories") config.data.model_version_path.mkdir(parents=True, exist_ok=True) setup_logging(config.data.model_version_path / "train.log", log_level) config.dump_config(config.data.model_version_path) + log.info(f"Running on {jax.devices()}") callbacks = initialize_callbacks(config.callbacks, config.data.model_version_path) loss_fn = initialize_loss_fn(config.loss) From e59b5d4f415a65d3b78ec41960b7dfa96a3fbd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 09:59:11 +0200 Subject: [PATCH 141/192] adde info log for training end --- apax/train/run.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apax/train/run.py b/apax/train/run.py index bc1bdf68..4b0fd77f 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -147,3 +147,4 @@ def run(user_config, log_level="error"): disable_batch_pbar=config.progress_bar.disable_batch_pbar, is_ensemble=config.n_models > 1, ) + log.info("Finished training") From f5daba87f6324e88b611e5551171af98591def3f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 08:06:06 +0000 Subject: [PATCH 142/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 9f77864c..aae54123 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -130,12 +130,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From d75ef8888c6db93a156fc2f173b26e3ee56a410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 11:21:35 +0200 Subject: [PATCH 143/192] removed debugging XLA options --- apax/__init__.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/apax/__init__.py b/apax/__init__.py index 2e2de880..5c5646ce 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -1,27 +1,8 @@ import os -# Set this to True to run the model on CPU only. -USE_CPU_ONLY = True - -flags = os.environ.get("XLA_FLAGS", "") -if USE_CPU_ONLY: - flags += " --xla_force_host_platform_device_count=2" # Simulate 8 devices - # Enforce CPU-only execution - os.environ["CUDA_VISIBLE_DEVICES"] = "" -else: - # GPU flags - flags += ( - "--xla_gpu_enable_triton_softmax_fusion=true " - "--xla_gpu_triton_gemm_any=false " - "--xla_gpu_enable_async_collectives=true " - "--xla_gpu_enable_latency_hiding_scheduler=true " - "--xla_gpu_enable_highest_priority_async_stream=true " - ) -os.environ["XLA_FLAGS"] = flags - - import jax + os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" jax.config.update("jax_enable_x64", True) From 159edc337217e3be53543448590ded4d5c8c4f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 11:22:38 +0200 Subject: [PATCH 144/192] added automatic dataparallel training --- apax/config/train_config.py | 3 +++ apax/data/input_pipeline.py | 24 ++++++++++++++++-------- apax/data/preprocessing.py | 32 +++++++++++++------------------- apax/train/run.py | 1 + apax/train/trainer.py | 23 +++++++++++++---------- 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 3cd5f57c..f8e083a9 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -298,6 +298,8 @@ class Config(BaseModel, frozen=True, extra="forbid"): callbacks: List of :class: `callback` configurations. progress_bar: Progressbar configuration. checkpoints: Checkpoint configuration. + data_parallel: Automatically uses all available GPUs for data parallel training. + Set to false to force single device training. """ n_epochs: PositiveInt @@ -305,6 +307,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): seed: int = 1 n_models: int = 1 n_jitted_steps: int = 1 + data_parallel: int = True data: DataConfig model: ModelConfig = ModelConfig() diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 539d5ed8..dd794933 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -201,7 +201,7 @@ def __iter__(self): space = self.n_data - self.count self.enqueue(space) - def shuffle_and_batch(self): + def shuffle_and_batch(self, sharding=None): """Shuffles and batches the inputs/labels. This function prepares the inputs and labels for the whole training and prefetches the data. @@ -223,10 +223,12 @@ def shuffle_and_batch(self): ).batch(batch_size=self.batch_size) if self.n_jit_steps > 1: ds = ds.batch(batch_size=self.n_jit_steps) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2, sharding) + ds = prefetch_to_single_device( + ds.as_numpy_iterator(), 2, sharding, n_step_jit=self.n_jit_steps > 1 + ) return ds - def batch(self, sharding) -> Iterator[jax.Array]: + def batch(self, sharding=None) -> Iterator[jax.Array]: ds = ( tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() @@ -235,7 +237,9 @@ def batch(self, sharding) -> Iterator[jax.Array]: .repeat(self.n_epochs) ) ds = ds.batch(batch_size=self.batch_size) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + ds = prefetch_to_single_device( + ds.as_numpy_iterator(), 2, sharding, n_step_jit=self.n_jit_steps > 1 + ) return ds def cleanup(self): @@ -261,7 +265,7 @@ def __iter__(self): self.count = 0 self.enqueue(space) - def shuffle_and_batch(self): + def shuffle_and_batch(self, sharding=None): """Shuffles and batches the inputs/labels. This function prepares the inputs and labels for the whole training and prefetches the data. @@ -279,15 +283,19 @@ def shuffle_and_batch(self): ).batch(batch_size=self.batch_size) if self.n_jit_steps > 1: ds = ds.batch(batch_size=self.n_jit_steps) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + ds = prefetch_to_single_device( + ds.as_numpy_iterator(), 2, sharding, n_step_jit=self.n_jit_steps > 1 + ) return ds - def batch(self) -> Iterator[jax.Array]: + def batch(self, sharding=None) -> Iterator[jax.Array]: ds = tf.data.Dataset.from_generator( lambda: self, output_signature=self.make_signature() ) ds = ds.batch(batch_size=self.batch_size) - ds = prefetch_to_single_device(ds.as_numpy_iterator(), 2) + ds = prefetch_to_single_device( + ds.as_numpy_iterator(), 2, sharding, n_step_jit=self.n_jit_steps > 1 + ) return ds diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 715cff24..dc2da7a4 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -53,7 +53,7 @@ def get_shrink_wrapped_cell(positions): return cell, cell_origin -def prefetch_to_single_device(iterator, size: int, sharding = None): +def prefetch_to_single_device(iterator, size: int, sharding=None, n_step_jit=False): """ inspired by https://flax.readthedocs.io/en/latest/_modules/flax/jax_utils.html#prefetch_to_device @@ -61,27 +61,21 @@ def prefetch_to_single_device(iterator, size: int, sharding = None): """ queue = collections.deque() - n_devices = 2 - multistep_jit = True - slice_start = 1 - shape = [n_devices] - if multistep_jit: - # replicate over multi-batch axis - # data shape: njit x bs x ... - slice_start = 2 - shape.insert(0, 1) + if sharding: + n_devices = len(sharding._devices) + slice_start = 1 + shape = [n_devices] + if n_step_jit: + # replicate over multi-batch axis + # data shape: njit x bs x ... + slice_start = 2 + shape.insert(0, 1) def _prefetch(x: jax.Array): - - print(x.shape) - # quit() - shape if sharding: - remaining_axes = [1]*len(x.shape[slice_start:]) - shape = tuple(shape + remaining_axes) - x = jax.device_put(x, sharding.reshape(shape)) - print(x.devices()) - quit() + remaining_axes = [1] * len(x.shape[slice_start:]) + final_shape = tuple(shape + remaining_axes) + x = jax.device_put(x, sharding.reshape(final_shape)) else: x = jnp.asarray(x) return x diff --git a/apax/train/run.py b/apax/train/run.py index fe408ab6..163e2849 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -145,4 +145,5 @@ def run(user_config, log_level="error"): patience=config.patience, disable_pbar=config.progress_bar.disable_epoch_pbar, is_ensemble=config.n_models > 1, + data_parallel=config.data_parallel, ) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index f9a99924..913b4351 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -30,6 +30,7 @@ def fit( patience: Optional[int] = None, disable_pbar: bool = False, is_ensemble=False, + data_parallel=True, ): log.info("Beginning Training") callbacks.on_train_begin() @@ -50,12 +51,15 @@ def fit( f"n_epochs <= current epoch from checkpoint ({n_epochs} <= {start_epoch})" ) - from jax.experimental import mesh_utils from jax.sharding import PositionalSharding - sharding = PositionalSharding(mesh_utils.create_device_mesh((len(jax.devices()),))) - jax.device_put(state, sharding.replicate()) + devices = len(jax.devices()) + if devices > 1 and data_parallel: + sharding = PositionalSharding(mesh_utils.create_device_mesh((devices,))) + state = jax.device_put(state, sharding.replicate()) + else: + sharding = None train_steps_per_epoch = train_ds.steps_per_epoch() batch_train_ds = train_ds.shuffle_and_batch(sharding) @@ -64,9 +68,6 @@ def fit( val_steps_per_epoch = val_ds.steps_per_epoch() batch_val_ds = val_ds.batch(sharding) - - - best_loss = np.inf early_stopping_counter = 0 epoch_loss = {} @@ -120,10 +121,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) From 5933ded410efaa24e85ea05a4448a6acaec0a082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 11:24:32 +0200 Subject: [PATCH 145/192] remove debug num epuchs and buffer size in input pipeline --- apax/data/input_pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index dd794933..d4d6b439 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -53,8 +53,8 @@ def __init__( self.sample_atoms = atoms[0] self.inputs = atoms_to_inputs(atoms) - self.n_epochs = 100 - self.buffer_size = 100 + self.n_epochs = n_epochs + self.buffer_size = buffer_size max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) self.max_atoms = max_atoms From 2b66ddf9e032a61d8ab7a1a3e9de578088c3b33b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:27:06 +0000 Subject: [PATCH 146/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 913b4351..17959eca 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -121,12 +121,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 59c0bd02000aaae3d81a9d8e1f1556ed352e15ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 11:28:50 +0200 Subject: [PATCH 147/192] moved sharding imports to the top --- apax/train/trainer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 913b4351..e0e138e6 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -8,6 +8,8 @@ import jax.numpy as jnp import numpy as np from clu import metrics +from jax.experimental import mesh_utils +from jax.sharding import PositionalSharding from tqdm import trange from apax.data.input_pipeline import InMemoryDataset @@ -51,9 +53,6 @@ def fit( f"n_epochs <= current epoch from checkpoint ({n_epochs} <= {start_epoch})" ) - from jax.experimental import mesh_utils - from jax.sharding import PositionalSharding - devices = len(jax.devices()) if devices > 1 and data_parallel: sharding = PositionalSharding(mesh_utils.create_device_mesh((devices,))) From f1a57aacfcca2d9423e23c9241856f9781c43f67 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:29:03 +0000 Subject: [PATCH 148/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apax/__init__.py b/apax/__init__.py index 5c5646ce..de4b9e6e 100644 --- a/apax/__init__.py +++ b/apax/__init__.py @@ -2,7 +2,6 @@ import jax - os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" jax.config.update("jax_enable_x64", True) From a2e4c995e8dc047fa277bc7069b6be6ee5d3ca46 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Thu, 4 Apr 2024 15:32:34 +0200 Subject: [PATCH 149/192] unit fix --- apax/bal/api.py | 2 ++ apax/data/input_pipeline.py | 30 ++++++++++++++----------- apax/train/eval.py | 6 ++++- apax/train/run.py | 4 ++++ tests/regression_tests/apax_config.yaml | 9 ++++---- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index f891c5c9..3de60677 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -91,6 +91,8 @@ def kernel_selection( bs=processing_batch_size, n_epochs=1, ignore_labels=True, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, ) _, init_box = dataset.init_input() diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 082415a0..836ad9ae 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -11,7 +11,7 @@ import tensorflow as tf from apax.data.preprocessing import compute_nl, prefetch_to_single_device -from apax.utils.convert import atoms_to_inputs, atoms_to_labels +from apax.utils.convert import atoms_to_inputs, atoms_to_labels, unit_dict log = logging.getLogger(__name__) @@ -44,33 +44,37 @@ def __init__( n_epochs, buffer_size=1000, n_jit_steps=1, + pos_unit: str = "Ang", + energy_unit: str = "eV", pre_shuffle=False, ignore_labels=False, cache_path=".", ) -> None: + + self.n_epochs = n_epochs + self.cutoff = cutoff + self.n_jit_steps = n_jit_steps + self.buffer_size = buffer_size + self.n_data = len(atoms) + self.batch_size = self.validate_batch_size(bs) + self.pos_unit = pos_unit + if pre_shuffle: shuffle(atoms) self.sample_atoms = atoms[0] - self.inputs = atoms_to_inputs(atoms) + self.inputs = atoms_to_inputs(atoms, self.pos_unit) - self.n_epochs = n_epochs - self.buffer_size = buffer_size - - max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) + max_atoms, max_nbrs = find_largest_system(self.inputs, self.cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs if atoms[0].calc and not ignore_labels: - self.labels = atoms_to_labels(atoms) + self.labels = atoms_to_labels(atoms, self.pos_unit, energy_unit) else: self.labels = None - self.n_data = len(atoms) self.count = 0 - self.cutoff = cutoff self.buffer = deque() - self.batch_size = self.validate_batch_size(bs) - self.n_jit_steps = n_jit_steps self.file = Path(cache_path) / str(uuid.uuid4()) self.enqueue(min(self.buffer_size, self.n_data)) @@ -164,8 +168,8 @@ def make_signature(self) -> tf.TensorSpec: def init_input(self) -> Dict[str, np.ndarray]: """Returns first batch of inputs and labels to init the model.""" - positions = self.sample_atoms.positions - box = self.sample_atoms.cell.array + positions = self.sample_atoms.positions * unit_dict[self.pos_unit] + box = self.sample_atoms.cell.array * unit_dict[self.pos_unit] idx, offsets = compute_nl(positions, box, self.cutoff) inputs = ( positions, diff --git a/apax/train/eval.py b/apax/train/eval.py index f15a6da3..2159c197 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -123,7 +123,11 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): atoms_list = load_test_data(config, model_version_path, eval_path, n_test) test_ds = OTFInMemoryDataset( - atoms_list, config.model.r_max, config.data.valid_batch_size + atoms_list, + config.model.r_max, + config.data.valid_batch_size, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, ) _, init_box = test_ds.init_input() diff --git a/apax/train/run.py b/apax/train/run.py index fe408ab6..dff8ad31 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -63,6 +63,8 @@ def initialize_datasets(config: Config): config.n_epochs, config.data.shuffle_buffer_size, config.n_jitted_steps, + config.data.pos_unit, + config.data.energy_unit, pre_shuffle=True, cache_path=config.data.model_version_path, ) @@ -71,6 +73,8 @@ def initialize_datasets(config: Config): config.model.r_max, config.data.valid_batch_size, config.n_epochs, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, cache_path=config.data.model_version_path, ) ds_stats = compute_scale_shift_parameters( diff --git a/tests/regression_tests/apax_config.yaml b/tests/regression_tests/apax_config.yaml index b112941e..f0d0e7ad 100644 --- a/tests/regression_tests/apax_config.yaml +++ b/tests/regression_tests/apax_config.yaml @@ -50,13 +50,14 @@ metrics: # - mse loss: - - loss_type: structures - name: energy + - name: energy + atoms_exponent: 2 weight: 1.0 - - loss_type: structures - name: forces + - name: forces + atoms_exponent: 1 weight: 8.0 - loss_type: cosine_sim + atoms_exponent: 1 name: forces weight: 0.1 # - loss_type: structures From baa6db0038b7e5e724691f00f4238698130df1e6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:33:37 +0000 Subject: [PATCH 150/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/data/input_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 836ad9ae..267f7d1b 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -50,7 +50,7 @@ def __init__( ignore_labels=False, cache_path=".", ) -> None: - + self.n_epochs = n_epochs self.cutoff = cutoff self.n_jit_steps = n_jit_steps From 93a05f045051052f711d4a5d47709aa72f713db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 15:55:21 +0200 Subject: [PATCH 151/192] sketch of nl fix --- apax/data/input_pipeline.py | 22 +++++++++++++--------- apax/data/preprocessing.py | 12 ++++++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 082415a0..5664e972 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -3,8 +3,9 @@ from collections import deque from pathlib import Path from random import shuffle -from typing import Dict, Iterator +from typing import Dict, Iterator, List +from ase import Atoms import jax import jax.numpy as jnp import numpy as np @@ -23,12 +24,12 @@ def pad_nl(idx, offsets, max_neighbors): return idx, offsets -def find_largest_system(inputs: dict[str, np.ndarray], r_max) -> tuple[int]: - max_atoms = np.max(inputs["n_atoms"]) +def find_largest_system(atoms_list: List[Atoms], r_max) -> tuple[int]: + max_atoms = np.max([atoms.numbers.shape[0] for atoms in atoms_list]) max_nbrs = 0 - for position, box in zip(inputs["positions"], inputs["box"]): - neighbor_idxs, _ = compute_nl(position, box, r_max) + for atoms in atoms_list: + neighbor_idxs, _ = compute_nl(atoms, r_max) n_neighbors = neighbor_idxs.shape[1] max_nbrs = max(max_nbrs, n_neighbors) @@ -52,13 +53,16 @@ def __init__( shuffle(atoms) self.sample_atoms = atoms[0] self.inputs = atoms_to_inputs(atoms) + self.atoms = atoms self.n_epochs = n_epochs self.buffer_size = buffer_size - max_atoms, max_nbrs = find_largest_system(self.inputs, cutoff) + max_atoms, max_nbrs = find_largest_system(atoms, cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs + # print(max_atoms, max_nbrs) + # quit() if atoms[0].calc and not ignore_labels: self.labels = atoms_to_labels(atoms) @@ -94,8 +98,8 @@ def validate_batch_size(self, batch_size: int) -> int: return batch_size def prepare_data(self, i): - inputs = {k: v[i] for k, v in self.inputs.items()} - idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) + inputs = {k: v[i] for k, v in self.inputs.items()} # inputs["positions"], inputs["box"] + idx, offsets = compute_nl(self.atoms[i], self.cutoff) inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] @@ -166,7 +170,7 @@ def init_input(self) -> Dict[str, np.ndarray]: """Returns first batch of inputs and labels to init the model.""" positions = self.sample_atoms.positions box = self.sample_atoms.cell.array - idx, offsets = compute_nl(positions, box, self.cutoff) + idx, offsets = compute_nl(self.sample_atoms, self.cutoff) inputs = ( positions, self.sample_atoms.numbers, diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index b52efdbf..32827644 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -10,12 +10,12 @@ log = logging.getLogger(__name__) -def compute_nl(position, box, r_max): - if np.all(box < 1e-6): - cell, cell_origin = get_shrink_wrapped_cell(position) +def compute_nl(atoms, r_max): + if np.all(atoms.cell.array < 1e-6): + cell, cell_origin = get_shrink_wrapped_cell(atoms.positions) idxs_i, idxs_j = neighbour_list( "ij", - positions=position, + positions=atoms.positions, cutoff=r_max, cell=cell, cell_origin=cell_origin, @@ -30,11 +30,11 @@ def compute_nl(position, box, r_max): else: idxs_i, idxs_j, offsets = neighbour_list( "ijS", - positions=position, + atoms = atoms, cutoff=r_max, - cell=box, ) neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) + box = atoms.cell.array offsets = np.matmul(offsets, box) return neighbor_idxs, offsets From 3fb591791258114dd390c02c7f3b6f35415c24f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 16:33:25 +0200 Subject: [PATCH 152/192] fixed periodicity check bug --- apax/utils/convert.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index b6bfd76e..07d252fb 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -38,6 +38,14 @@ def prune_dict(data_dict): pruned = {key: val for key, val in data_dict.items() if len(val) != 0} return pruned +def is_periodic(box): + pbc_dims = np.any(np.abs(box) > 1e-6) + if np.all(pbc_dims == True) or np.all(pbc_dims == False): + return pbc_dims + else: + msg = f"Only 3D periodic and gas phase system supported at the moment. Found {box}" + raise ValueError(msg) + def atoms_to_inputs( atoms_list: list[Atoms], @@ -67,19 +75,21 @@ def atoms_to_inputs( } box = atoms_list[0].cell.array - pbc = np.all(box > 1e-6) + pbc = is_periodic(box) for atoms in atoms_list: box = (atoms.cell.array * unit_dict[pos_unit]).astype(DTYPE) box = box.T # takes row and column convention of ase into account inputs["box"].append(box) - if pbc != np.all(box > 1e-6): + current_pbc = is_periodic(box) + + if pbc != current_pbc: raise ValueError( "Apax does not support dataset periodic and non periodic structures" ) - if np.all(box < 1e-6): + if not current_pbc: inputs["positions"].append( (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) ) From 04cc7328fa49fcbeea4e046a9de1e7d382cec9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 16:36:39 +0200 Subject: [PATCH 153/192] removed self.inputs form dataset --- apax/data/input_pipeline.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 5664e972..65fc2ec7 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -39,7 +39,7 @@ def find_largest_system(atoms_list: List[Atoms], r_max) -> tuple[int]: class InMemoryDataset: def __init__( self, - atoms, + atoms_list, cutoff, bs, n_epochs, @@ -50,26 +50,29 @@ def __init__( cache_path=".", ) -> None: if pre_shuffle: - shuffle(atoms) - self.sample_atoms = atoms[0] - self.inputs = atoms_to_inputs(atoms) + shuffle(atoms_list) + self.sample_atoms = atoms_list[0] + # self.inputs = atoms_to_inputs(atoms) self.atoms = atoms self.n_epochs = n_epochs self.buffer_size = buffer_size - max_atoms, max_nbrs = find_largest_system(atoms, cutoff) + max_atoms, max_nbrs = find_largest_system(atoms_list, cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs # print(max_atoms, max_nbrs) # quit() - if atoms[0].calc and not ignore_labels: - self.labels = atoms_to_labels(atoms) - else: - self.labels = None + self.compute_labels = False + if atoms_list[0].calc and not ignore_labels: + self.compute_labels = True + # if atoms[0].calc and not ignore_labels: + # self.labels = atoms_to_labels(atoms) + # else: + # self.labels = None - self.n_data = len(atoms) + self.n_data = len(atoms_list) self.count = 0 self.cutoff = cutoff self.buffer = deque() @@ -98,7 +101,9 @@ def validate_batch_size(self, batch_size: int) -> int: return batch_size def prepare_data(self, i): - inputs = {k: v[i] for k, v in self.inputs.items()} # inputs["positions"], inputs["box"] + # inputs = {k: v[i] for k, v in self.inputs.items()} + atoms = self.atoms_list[i] + inputs = atoms_to_inputs(atoms, self.pos_unit) idx, offsets = compute_nl(self.atoms[i], self.cutoff) inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) From ac6030046f0a98f310ea37dcb06c9a887cb03722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Thu, 4 Apr 2024 21:21:20 +0200 Subject: [PATCH 154/192] sketch of fix --- apax/data/input_pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 071b724b..a6775f6b 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -122,10 +122,10 @@ def prepare_data(self, i): inputs["n_atoms"], (0, zeros_to_add), "constant" ).astype(np.int16) - if not self.labels: + if not self.compute_labels: return inputs - labels = {k: v[i] for k, v in self.labels.items()} + # labels = {k: v[i] for k, v in self.labels.items()} if "forces" in labels: labels["forces"] = np.pad( labels["forces"], ((0, zeros_to_add), (0, 0)), "constant" From 2c081102519f0313f5b1efcc3e16184a081e1507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 10:41:25 +0200 Subject: [PATCH 155/192] fixed neighborlist computatoin for periodic systems --- apax/data/input_pipeline.py | 43 ++++++++++++++----------------------- apax/data/preprocessing.py | 26 +++++++++++++--------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index a6775f6b..156f5baf 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -24,12 +24,13 @@ def pad_nl(idx, offsets, max_neighbors): return idx, offsets -def find_largest_system(atoms_list: List[Atoms], r_max) -> tuple[int]: - max_atoms = np.max([atoms.numbers.shape[0] for atoms in atoms_list]) +def find_largest_system(inputs, r_max) -> tuple[int]: + positions, boxes = inputs["positions"], inputs["box"] + max_atoms = np.max(inputs["n_atoms"]) max_nbrs = 0 - for atoms in atoms_list: - neighbor_idxs, _ = compute_nl(atoms, r_max) + for pos, box in zip(positions, boxes): + neighbor_idxs, _ = compute_nl(pos, box, r_max) n_neighbors = neighbor_idxs.shape[1] max_nbrs = max(max_nbrs, n_neighbors) @@ -63,22 +64,15 @@ def __init__( if pre_shuffle: shuffle(atoms_list) self.sample_atoms = atoms_list[0] - # self.inputs = atoms_to_inputs(atoms, self.pos_unit) - self.atoms_list = atoms_list + self.inputs = atoms_to_inputs(atoms_list, self.pos_unit) - max_atoms, max_nbrs = find_largest_system(atoms_list, self.cutoff) + max_atoms, max_nbrs = find_largest_system(self.inputs, self.cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs - # print(max_atoms, max_nbrs) - # quit() - - self.compute_labels = False if atoms_list[0].calc and not ignore_labels: - self.compute_labels = True - # if atoms[0].calc and not ignore_labels: - # self.labels = atoms_to_labels(atoms) - # else: - # self.labels = None + self.labels = atoms_to_labels(atoms_list) + else: + self.labels = None self.count = 0 self.buffer = deque() @@ -105,10 +99,8 @@ def validate_batch_size(self, batch_size: int) -> int: return batch_size def prepare_data(self, i): - # inputs = {k: v[i] for k, v in self.inputs.items()} - atoms = self.atoms_list[i] - inputs = atoms_to_inputs(atoms, self.pos_unit) - idx, offsets = compute_nl(self.atoms[i], self.cutoff) + inputs = {k: v[i] for k, v in self.inputs.items()} + idx, offsets = compute_nl(inputs["positions"], inputs["box"], self.cutoff) inputs["idx"], inputs["offsets"] = pad_nl(idx, offsets, self.max_nbrs) zeros_to_add = self.max_atoms - inputs["numbers"].shape[0] @@ -118,19 +110,15 @@ def prepare_data(self, i): inputs["numbers"] = np.pad( inputs["numbers"], (0, zeros_to_add), "constant" ).astype(np.int16) - inputs["n_atoms"] = np.pad( - inputs["n_atoms"], (0, zeros_to_add), "constant" - ).astype(np.int16) - if not self.compute_labels: + if not self.labels: return inputs - # labels = {k: v[i] for k, v in self.labels.items()} + labels = {k: v[i] for k, v in self.labels.items()} if "forces" in labels: labels["forces"] = np.pad( labels["forces"], ((0, zeros_to_add), (0, 0)), "constant" ) - inputs = {k: tf.constant(v) for k, v in inputs.items()} labels = {k: tf.constant(v) for k, v in labels.items()} return (inputs, labels) @@ -179,7 +167,8 @@ def init_input(self) -> Dict[str, np.ndarray]: """Returns first batch of inputs and labels to init the model.""" positions = self.sample_atoms.positions * unit_dict[self.pos_unit] box = self.sample_atoms.cell.array * unit_dict[self.pos_unit] - idx, offsets = compute_nl(self.sample_atoms, self.cutoff) + # For an input sample, it does not matter whether pos is fractional or cartesian + idx, offsets = compute_nl(positions, box, self.cutoff) inputs = ( positions, self.sample_atoms.numbers, diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 32827644..1c6cd0f6 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -10,31 +10,37 @@ log = logging.getLogger(__name__) -def compute_nl(atoms, r_max): - if np.all(atoms.cell.array < 1e-6): - cell, cell_origin = get_shrink_wrapped_cell(atoms.positions) +def compute_nl(positions, box, r_max): + """Computes the NL for a single structure. + For periodic systems, positions are assumed to be in + fractional coordinates. + """ + if np.all(box < 1e-6): + box, box_origin = get_shrink_wrapped_cell(positions) idxs_i, idxs_j = neighbour_list( "ij", - positions=atoms.positions, + positions=positions, cutoff=r_max, - cell=cell, - cell_origin=cell_origin, + cell=box, + cell_origin=box_origin, pbc=[False, False, False], ) - neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) + neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int16) n_neighbors = neighbor_idxs.shape[1] offsets = np.full([n_neighbors, 3], 0) else: + positions = positions @ box idxs_i, idxs_j, offsets = neighbour_list( "ijS", - atoms = atoms, + positions=positions, cutoff=r_max, + cell=box, + pbc=[True, True, True] ) - neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int32) - box = atoms.cell.array + neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int16) offsets = np.matmul(offsets, box) return neighbor_idxs, offsets From 4aa8eae7117db2f2e785b19da409e7460b9fdad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 10:42:10 +0200 Subject: [PATCH 156/192] linting --- apax/data/input_pipeline.py | 4 +--- apax/data/preprocessing.py | 6 +----- apax/train/trainer.py | 10 ++++++---- apax/utils/convert.py | 5 ++++- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 156f5baf..43ae1dda 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -3,9 +3,8 @@ from collections import deque from pathlib import Path from random import shuffle -from typing import Dict, Iterator, List +from typing import Dict, Iterator -from ase import Atoms import jax import jax.numpy as jnp import numpy as np @@ -52,7 +51,6 @@ def __init__( ignore_labels=False, cache_path=".", ) -> None: - self.n_epochs = n_epochs self.cutoff = cutoff self.n_jit_steps = n_jit_steps diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 1c6cd0f6..c68b33ba 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -34,11 +34,7 @@ def compute_nl(positions, box, r_max): else: positions = positions @ box idxs_i, idxs_j, offsets = neighbour_list( - "ijS", - positions=positions, - cutoff=r_max, - cell=box, - pbc=[True, True, True] + "ijS", positions=positions, cutoff=r_max, cell=box, pbc=[True, True, True] ) neighbor_idxs = np.array([idxs_i, idxs_j], dtype=np.int16) offsets = np.matmul(offsets, box) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 8c040a3f..6d6bc0f0 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -107,10 +107,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index 07d252fb..c537bcf2 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -38,12 +38,15 @@ def prune_dict(data_dict): pruned = {key: val for key, val in data_dict.items() if len(val) != 0} return pruned + def is_periodic(box): pbc_dims = np.any(np.abs(box) > 1e-6) if np.all(pbc_dims == True) or np.all(pbc_dims == False): return pbc_dims else: - msg = f"Only 3D periodic and gas phase system supported at the moment. Found {box}" + msg = ( + f"Only 3D periodic and gas phase system supported at the moment. Found {box}" + ) raise ValueError(msg) From 46a8a6519e09aba7e86115ee82d59f19f7022488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 13:04:13 +0200 Subject: [PATCH 157/192] readded unit conversion --- apax/data/input_pipeline.py | 4 ++-- apax/train/run.py | 4 ++-- apax/train/trainer.py | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 43ae1dda..f3a0a267 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -62,13 +62,13 @@ def __init__( if pre_shuffle: shuffle(atoms_list) self.sample_atoms = atoms_list[0] - self.inputs = atoms_to_inputs(atoms_list, self.pos_unit) + self.inputs = atoms_to_inputs(atoms_list, pos_unit) max_atoms, max_nbrs = find_largest_system(self.inputs, self.cutoff) self.max_atoms = max_atoms self.max_nbrs = max_nbrs if atoms_list[0].calc and not ignore_labels: - self.labels = atoms_to_labels(atoms_list) + self.labels = atoms_to_labels(atoms_list, pos_unit, energy_unit) else: self.labels = None diff --git a/apax/train/run.py b/apax/train/run.py index dff8ad31..e81b11ff 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -63,8 +63,8 @@ def initialize_datasets(config: Config): config.n_epochs, config.data.shuffle_buffer_size, config.n_jitted_steps, - config.data.pos_unit, - config.data.energy_unit, + pos_unit=config.data.pos_unit, + energy_unit=config.data.energy_unit, pre_shuffle=True, cache_path=config.data.model_version_path, ) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 6d6bc0f0..29d8cb2c 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -84,7 +84,6 @@ def fit( epoch_loss["train_loss"] += jnp.mean(batch_loss) callbacks.on_train_batch_end(batch=batch_idx) - epoch_loss["train_loss"] /= train_steps_per_epoch epoch_loss["train_loss"] = float(epoch_loss["train_loss"]) From 1dc1203fdf2bcc68d46d831419f787f01fd7d0f3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:31:26 +0000 Subject: [PATCH 158/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/train/trainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 9f77864c..aae54123 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -130,12 +130,10 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update( - { - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - } - ) + epoch_metrics.update({ + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + }) epoch_metrics.update({**epoch_loss}) From 2305f5045fd4691dd9a2e794a6c2129e1f2a74e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 13:35:05 +0200 Subject: [PATCH 159/192] linting --- apax/utils/convert.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apax/utils/convert.py b/apax/utils/convert.py index c537bcf2..a7d4cc45 100644 --- a/apax/utils/convert.py +++ b/apax/utils/convert.py @@ -41,7 +41,7 @@ def prune_dict(data_dict): def is_periodic(box): pbc_dims = np.any(np.abs(box) > 1e-6) - if np.all(pbc_dims == True) or np.all(pbc_dims == False): + if np.all(pbc_dims == True) or np.all(pbc_dims == False): # noqa: E712 return pbc_dims else: msg = ( @@ -85,22 +85,22 @@ def atoms_to_inputs( box = box.T # takes row and column convention of ase into account inputs["box"].append(box) - current_pbc = is_periodic(box) + is_pbc = is_periodic(box) - if pbc != current_pbc: + if pbc != is_pbc: raise ValueError( "Apax does not support dataset periodic and non periodic structures" ) - if not current_pbc: - inputs["positions"].append( - (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) - ) - else: + if is_pbc: inv_box = np.linalg.inv(box) pos = (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) frac_pos = space.transform(inv_box, pos) inputs["positions"].append(np.array(frac_pos)) + else: + inputs["positions"].append( + (atoms.positions * unit_dict[pos_unit]).astype(DTYPE) + ) inputs["numbers"].append(atoms.numbers.astype(np.int16)) inputs["n_atoms"].append(len(atoms)) From fcb5482ebc60f673aba2cbf84cb68f33f9faf7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 15:40:26 +0200 Subject: [PATCH 160/192] poetry update --- poetry.lock | 469 ++++++++++++++++++++++++---------------------------- 1 file changed, 213 insertions(+), 256 deletions(-) diff --git a/poetry.lock b/poetry.lock index 94d4fc3b..f950d510 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,14 @@ -# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "absl-py" -version = "2.1.0" +version = "1.4.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff"}, - {file = "absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308"}, + {file = "absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d"}, + {file = "absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47"}, ] [[package]] @@ -581,13 +581,13 @@ files = [ [[package]] name = "comm" -version = "0.2.1" +version = "0.2.2" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, - {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, ] [package.dependencies] @@ -852,13 +852,6 @@ files = [ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa42a605d099ee7d41ba2b5fb75e21423951fd26e5d50583a00471238fb3021d"}, {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b7764de0d855338abefc6e3ee9fe40d301668310aa3baea3f778ff051f4393"}, {file = "dm_tree-0.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:a5d819c38c03f0bb5b3b3703c60e4b170355a0fc6b5819325bf3d4ceb3ae7e80"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea9e59e0451e7d29aece402d9f908f2e2a80922bcde2ebfd5dcb07750fcbfee8"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:94d3f0826311f45ee19b75f5b48c99466e4218a0489e81c0f0167bda50cacf22"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:435227cf3c5dc63f4de054cf3d00183790bd9ead4c3623138c74dde7f67f521b"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09964470f76a5201aff2e8f9b26842976de7889300676f927930f6285e256760"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75c5d528bb992981c20793b6b453e91560784215dffb8a5440ba999753c14ceb"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a94aba18a35457a1b5cd716fd7b46c5dafdc4cf7869b4bae665b91c4682a8e"}, - {file = "dm_tree-0.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:96a548a406a6fb15fe58f6a30a57ff2f2aafbf25f05afab00c8f5e5977b6c715"}, {file = "dm_tree-0.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8c60a7eadab64c2278861f56bca320b2720f163dca9d7558103c3b77f2416571"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af4b3d372f2477dcd89a6e717e4a575ca35ccc20cc4454a8a4b6f8838a00672d"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de287fabc464b8734be251e46e06aa9aa1001f34198da2b6ce07bd197172b9cb"}, @@ -949,11 +942,9 @@ files = [ ] [package.dependencies] -absl-py = {version = "*", optional = true, markers = "extra == \"etqdm\""} fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} numpy = {version = "*", optional = true, markers = "extra == \"enp\""} -tqdm = {version = "*", optional = true, markers = "extra == \"etqdm\""} typing_extensions = {version = "*", optional = true, markers = "extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} @@ -1682,13 +1673,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.3" +version = "6.29.4" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.3-py3-none-any.whl", hash = "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21"}, - {file = "ipykernel-6.29.3.tar.gz", hash = "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2"}, + {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, + {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, ] [package.dependencies] @@ -1715,13 +1706,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.22.1" +version = "8.23.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.22.1-py3-none-any.whl", hash = "sha256:869335e8cded62ffb6fac8928e5287a05433d6462e3ebaac25f4216474dd6bc4"}, - {file = "ipython-8.22.1.tar.gz", hash = "sha256:39c6f9efc079fb19bfb0f17eee903978fe9a290b1b82d68196c641cecb76ea22"}, + {file = "ipython-8.23.0-py3-none-any.whl", hash = "sha256:07232af52a5ba146dc3372c7bf52a0f890a23edf38d77caef8d53f9cdc2584c1"}, + {file = "ipython-8.23.0.tar.gz", hash = "sha256:7468edaf4f6de3e1b912e57f66c241e6fd3c7099f2ec2136e239e142e800274d"}, ] [package.dependencies] @@ -1735,12 +1726,14 @@ prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5.13.0" +typing-extensions = {version = "*", markers = "python_version < \"3.12\""} [package.extras] -all = ["ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]", "ipython[test,test-extra]"] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] kernel = ["ipykernel"] +matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] @@ -1776,13 +1769,13 @@ files = [ [[package]] name = "jax" -version = "0.4.25" +version = "0.4.26" description = "Differentiate, compile, and transform Numpy code." optional = false python-versions = ">=3.9" files = [ - {file = "jax-0.4.25-py3-none-any.whl", hash = "sha256:8158c837e5ecc195074b421609e85329a962785b36f9fe5ff53e844e8ad87dbc"}, - {file = "jax-0.4.25.tar.gz", hash = "sha256:a8ee189c782de2b7b2ffb64a8916da380b882a617e2769aa429b71d79747b982"}, + {file = "jax-0.4.26-py3-none-any.whl", hash = "sha256:50dc795148ee6b0735b48b477e5abc556aa3a4c7af5d6940dad08024a908b02f"}, + {file = "jax-0.4.26.tar.gz", hash = "sha256:2cce025d0a279ec630d550524749bc8efe25d2ff47240d2a7d4cfbc5090c5383"}, ] [package.dependencies] @@ -1796,45 +1789,43 @@ scipy = ">=1.9" [package.extras] australis = ["protobuf (>=3.13,<4)"] -ci = ["jaxlib (==0.4.24)"] -cpu = ["jaxlib (==0.4.25)"] -cuda = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-cudnn86 = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-local = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-pip = ["jaxlib (==0.4.25+cuda11.cudnn86)", "nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)", "nvidia-nccl-cu11 (>=2.18.3)"] -cuda12 = ["jax-cuda12-plugin (==0.4.25)", "jaxlib (==0.4.25)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] -cuda12-local = ["jaxlib (==0.4.25+cuda12.cudnn89)"] -cuda12-pip = ["jaxlib (==0.4.25+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] +ci = ["jaxlib (==0.4.25)"] +cpu = ["jaxlib (==0.4.26)"] +cuda = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12 = ["jax-cuda12-plugin (==0.4.26)", "jaxlib (==0.4.26)", "nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] +cuda12-cudnn89 = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12-local = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12-pip = ["jaxlib (==0.4.26+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] minimum-jaxlib = ["jaxlib (==0.4.20)"] -tpu = ["jaxlib (==0.4.25)", "libtpu-nightly (==0.1.dev20240224)", "requests"] +tpu = ["jaxlib (==0.4.26)", "libtpu-nightly (==0.1.dev20240403)", "requests"] [[package]] name = "jaxlib" -version = "0.4.25" +version = "0.4.26" description = "XLA library for JAX" optional = false python-versions = ">=3.9" files = [ - {file = "jaxlib-0.4.25-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:be1b26e96e80d42f54f77226a016717cb969d7d208d0dcb61997f19dc7b2d8e2"}, - {file = "jaxlib-0.4.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3b5cbd3a4f731636469cdaf06c4413208811ca458ee312647e8f3faca32f6445"}, - {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:89a011330aaeaf19027bba5e3236be155cc8d73d94aa9db84d817d414f4a7647"}, - {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:dcda74c7c8eb328cde8afeebcf21ec9240138fac54f9631a60b679a211f7e100"}, - {file = "jaxlib-0.4.25-cp310-cp310-win_amd64.whl", hash = "sha256:fd751b10e60c085dec42bec6c27c9905f5c57d12323190eea0df10ee14c574e0"}, - {file = "jaxlib-0.4.25-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:37da780cb545ca210bfa0402b5081452ad830bb06fe9e970fd16ad14d2fdc6a6"}, - {file = "jaxlib-0.4.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df7e2193b216e195dfc7a8aa14527eb52614ec3ba4c59a199af2f17195ae1c1"}, - {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:0ce2a25263e7504d575e8ba5ba4f53aef6fe274679785bcf87ab06b0aaec0b90"}, - {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:a0dd09cbb62583941872b6a198894e87a1b64d8e4dd6b53946dbb41d642b8f5f"}, - {file = "jaxlib-0.4.25-cp311-cp311-win_amd64.whl", hash = "sha256:dfb1ef8c2e6a01ecb60f8833552ff077cd593154fd75739050fba9148879a2a4"}, - {file = "jaxlib-0.4.25-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:425d6f3fa57ea1d1674ae84b5a3d3588ba0937f3c47fd4f166eb84c4240887b8"}, - {file = "jaxlib-0.4.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e97542bbd89f4316d2feb599119d8a43440ca151b7a165eff0fc127cf4512e7"}, - {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:c4e3bc32aea275e025e762612216954626478c9cf5c44131e248cdd17e361efd"}, - {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:dcfb71a7f559c13734584769ca30373bc4b73d0fe105790462370e49f35dcbe4"}, - {file = "jaxlib-0.4.25-cp312-cp312-win_amd64.whl", hash = "sha256:f7aa9682b6806e4197ad51294e87e77f04f5eee7ced4e841aa7ccc7320c6d96b"}, - {file = "jaxlib-0.4.25-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:6660b68741286bd4b849c149d86a8c36e448f7e39e1d483e79dab79ea300bf1b"}, - {file = "jaxlib-0.4.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32881f93d5de195a0fd19e091a2aa89418fa27f630d30c79b4613a51cff4d1c6"}, - {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ad1ab653265c33b8d54bdcc40867a8ffd61fea879176e4d4cd0b585fe52521fc"}, - {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:0fd113ab414de856f90f07264e6ccd0cb95d392f3579c0deab4ff0943ef75f73"}, - {file = "jaxlib-0.4.25-cp39-cp39-win_amd64.whl", hash = "sha256:b11aef2bd6cf873b39399fda122170b625776d977bbc56b4635f46c396279b8b"}, + {file = "jaxlib-0.4.26-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:f9060fd81d1b2a2c2069e998db2be04853c40a244ab9edb1caf1c5cbd2f70881"}, + {file = "jaxlib-0.4.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e61ded57e05764350f7065583d85ab9270e7f7ed6b9f9d9394fe6ff64d96aab7"}, + {file = "jaxlib-0.4.26-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d483aff58898bf37e341d6241cecb3e107aebe4ca237fe6267d4c18b7c09ea90"}, + {file = "jaxlib-0.4.26-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:22e943ed10faa7d85fd804ddc20581bf6fbcc60e114435c3b3327b9f1ebff895"}, + {file = "jaxlib-0.4.26-cp310-cp310-win_amd64.whl", hash = "sha256:eb0cc16efc6313eb100688a38078061caa3c907ebfa1d315485a08fd27f374dc"}, + {file = "jaxlib-0.4.26-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:de4b9a54cd96e6a732c1cf65ae2defdf6a01558a15db8bf6dbd8f40d363b085d"}, + {file = "jaxlib-0.4.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cbdcb95ac73f80ea3a82a53b8f0621f37dfb01ab0203de6fc6691a4e2396984"}, + {file = "jaxlib-0.4.26-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:6754ee0d4dd44f708c3826c51ce648c5e08cfc56cabf23d4f3b428971ab00094"}, + {file = "jaxlib-0.4.26-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:3069da7d75f5b4dd15350fffe6e6b86ca09c4b9fde60b10515edb09cef653335"}, + {file = "jaxlib-0.4.26-cp311-cp311-win_amd64.whl", hash = "sha256:516d2b573975bd666278badd650620d5edf3abb835978459d78f135e95419b04"}, + {file = "jaxlib-0.4.26-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:2c66fe8285fed13bcd44b7e10aa90a25a4a58af82450a4b18d0f1573c04a7797"}, + {file = "jaxlib-0.4.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9275761ae907ec0e812031bbae644f7a217e314e62d518c85d60ce686d3a3b0b"}, + {file = "jaxlib-0.4.26-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:597df919f00646d3f9c6feb2a39c9fa0fca00032f19cfe758916db3db30d416a"}, + {file = "jaxlib-0.4.26-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f084dd65f2b3cd804102d9cecf938d876cbbd54cb95308634020fc71b98fac79"}, + {file = "jaxlib-0.4.26-cp312-cp312-win_amd64.whl", hash = "sha256:72f117535d6dbc568adbcf6e1740037e0fe1d6e5b9558ea4158556005cf72bfc"}, + {file = "jaxlib-0.4.26-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0fea35b04cce0a6a758fd005132c02122dd49be5914d70c7d54e8eafdf3f352b"}, + {file = "jaxlib-0.4.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:520f71795c411b41cbea13488f1b17610780d7d9afc02ac5f9931a8c975780cb"}, + {file = "jaxlib-0.4.26-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d7bbb75f8e63c5ada57a386b7bfaac301f689149ba132509ccd0c865b2ebd4d2"}, + {file = "jaxlib-0.4.26-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:80b2440072da25d85634e98f755b8381781bd4c1ab4023b2ae0956c360124080"}, + {file = "jaxlib-0.4.26-cp39-cp39-win_amd64.whl", hash = "sha256:96c9a183d7a56572a5c1508de317a05badddfbbc8370a8fa8a2e548d5e059dc3"}, ] [package.dependencies] @@ -1843,8 +1834,7 @@ numpy = ">=1.22" scipy = ">=1.9" [package.extras] -cuda11-pip = ["nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)"] -cuda12-pip = ["nvidia-cublas-cu12", "nvidia-cuda-cupti-cu12", "nvidia-cuda-nvcc-cu12", "nvidia-cuda-runtime-cu12", "nvidia-cudnn-cu12 (>=8.9)", "nvidia-cufft-cu12", "nvidia-cusolver-cu12", "nvidia-cusparse-cu12"] +cuda12-pip = ["nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] [[package]] name = "jaxtyping" @@ -1945,13 +1935,13 @@ referencing = ">=0.31.0" [[package]] name = "jupyter-client" -version = "8.6.0" +version = "8.6.1" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, - {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, + {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, + {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, ] [package.dependencies] @@ -1967,13 +1957,13 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt [[package]] name = "jupyter-core" -version = "5.7.1" +version = "5.7.2" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, - {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, ] [package.dependencies] @@ -1983,7 +1973,7 @@ traitlets = ">=5.3" [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyterlab-pygments" @@ -2293,39 +2283,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.3" +version = "3.8.4" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, - {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, - {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, - {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, - {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, - {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, - {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, - {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, - {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, - {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, - {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, - {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, - {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, - {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, - {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, - {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, - {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, - {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, - {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, - {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, - {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, - {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, - {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, - {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, - {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, + {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, + {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, + {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, + {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, + {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, + {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, + {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, + {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, + {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, ] [package.dependencies] @@ -2333,7 +2323,7 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" kiwisolver = ">=1.3.1" -numpy = ">=1.21,<2" +numpy = ">=1.21" packaging = ">=20.0" pillow = ">=8" pyparsing = ">=2.3.1" @@ -2488,8 +2478,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, {version = ">=1.21.2", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, ] [package.extras] @@ -2651,13 +2641,13 @@ testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4, [[package]] name = "nbclient" -version = "0.9.0" +version = "0.10.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.9.0-py3-none-any.whl", hash = "sha256:a3a1ddfb34d4a9d17fc744d655962714a866639acd30130e9be84191cd97cd15"}, - {file = "nbclient-0.9.0.tar.gz", hash = "sha256:4b28c207877cf33ef3a9838cdc7a54c5ceff981194a82eac59d558f05487295e"}, + {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, + {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, ] [package.dependencies] @@ -2669,17 +2659,17 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] name = "nbconvert" -version = "7.16.1" +version = "7.16.3" description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.16.1-py3-none-any.whl", hash = "sha256:3188727dffadfdc9c6a1c7250729063d7bc78b355ad7aa023138afa030d1cd07"}, - {file = "nbconvert-7.16.1.tar.gz", hash = "sha256:e79e6a074f49ba3ed29428ed86487bf51509d9aab613bd8522ac08f6d28fd7fd"}, + {file = "nbconvert-7.16.3-py3-none-any.whl", hash = "sha256:ddeff14beeeedf3dd0bc506623e41e4507e551736de59df69a91f86700292b3b"}, + {file = "nbconvert-7.16.3.tar.gz", hash = "sha256:a6733b78ce3d47c3f85e504998495b07e6ea9cf9bf6ec1c98dda63ec6ad19142"}, ] [package.dependencies] @@ -2705,24 +2695,24 @@ docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sp qtpdf = ["nbconvert[qtpng]"] qtpng = ["pyqtwebengine (>=5.15)"] serve = ["tornado (>=6.1)"] -test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] webpdf = ["playwright"] [[package]] name = "nbformat" -version = "5.9.2" +version = "5.10.4" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" files = [ - {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"}, - {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"}, + {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, + {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, ] [package.dependencies] -fastjsonschema = "*" +fastjsonschema = ">=2.15" jsonschema = ">=2.6" -jupyter-core = "*" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" traitlets = ">=5.1" [package.extras] @@ -2893,13 +2883,13 @@ test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] [[package]] name = "orbax-checkpoint" -version = "0.5.7" +version = "0.5.9" description = "Orbax Checkpoint" optional = false python-versions = ">=3.9" files = [ - {file = "orbax_checkpoint-0.5.7-py3-none-any.whl", hash = "sha256:34aa0b206a4cff9ea29acc96f2a913d0616cb5bcd15272a9806bb0238dd7a38c"}, - {file = "orbax_checkpoint-0.5.7.tar.gz", hash = "sha256:de14549b899220a4f445453967c1ac2d7165b815253342587746005f03a9813b"}, + {file = "orbax_checkpoint-0.5.9-py3-none-any.whl", hash = "sha256:75ccc929122a0511c3e1b5233233f26f2c7fbd1d0734459cf6cf9972447cf2cf"}, + {file = "orbax_checkpoint-0.5.9.tar.gz", hash = "sha256:1fde8891433723157bf6e75d341094d1dabed1dbcfc7cfcfb381de088b468b60"}, ] [package.dependencies] @@ -2969,8 +2959,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -3028,18 +3018,18 @@ files = [ [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pathspec" @@ -3319,6 +3309,31 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "pyarrow" version = "15.0.2" @@ -3367,31 +3382,6 @@ files = [ [package.dependencies] numpy = ">=1.16.6,<2" -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -optional = false -python-versions = "*" -files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] - -[package.extras] -tests = ["pytest"] - [[package]] name = "pyasn1" version = "0.6.0" @@ -3430,13 +3420,13 @@ files = [ [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -3697,29 +3687,6 @@ files = [ {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, ] -[[package]] -name = "pywin32" -version = "306" -description = "Python for Window Extensions" -optional = false -python-versions = "*" -files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, -] - [[package]] name = "pyyaml" version = "6.0.1" @@ -3745,7 +3712,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3885,21 +3851,6 @@ files = [ [package.dependencies] cffi = {version = "*", markers = "implementation_name == \"pypy\""} -[[package]] -name = "referencing" -version = "0.33.0" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" - [[package]] name = "querystring-parser" version = "1.2.4" @@ -3914,6 +3865,21 @@ files = [ [package.dependencies] six = "*" +[[package]] +name = "referencing" +version = "0.34.0" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.34.0-py3-none-any.whl", hash = "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4"}, + {file = "referencing-0.34.0.tar.gz", hash = "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "requests" version = "2.31.0" @@ -4444,25 +4410,6 @@ lint = ["docutils-stubs", "flake8", "mypy"] standalone = ["Sphinx (>=5)"] test = ["pytest"] -[[package]] -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - [[package]] name = "sqlalchemy" version = "2.0.29" @@ -4566,6 +4513,25 @@ dev = ["build", "flake8"] doc = ["sphinx"] test = ["pytest", "pytest-cov"] +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + [[package]] name = "tensorboard" version = "2.15.2" @@ -4887,17 +4853,18 @@ tensorflow-rocm = ["tensorflow-rocm (>=2.15.0,<2.16.0)"] [[package]] name = "tensorflow-metadata" -version = "0.22.2" +version = "1.14.0" description = "Library and standards for schema and statistics." optional = false -python-versions = ">=2.7,<4" +python-versions = ">=3.8,<4" files = [ - {file = "tensorflow_metadata-0.22.2-py2.py3-none-any.whl", hash = "sha256:f9ffde743dd61f775f35872e79c4eefecbc539a8870e57b20359dc74726f06eb"}, + {file = "tensorflow_metadata-1.14.0-py3-none-any.whl", hash = "sha256:5ff79bf96f98c800fc08270b852663afe7e74d7e1f92b50ba1487bfc63894cdb"}, ] [package.dependencies] -googleapis-common-protos = "*" -protobuf = ">=3.7,<4" +absl-py = ">=0.9,<2.0.0" +googleapis-common-protos = ">=1.52.0,<2" +protobuf = ">=3.20.3,<4.21" [[package]] name = "tensorstore" @@ -4943,6 +4910,17 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] +[[package]] +name = "threadpoolctl" +version = "3.4.0" +description = "threadpoolctl" +optional = false +python-versions = ">=3.8" +files = [ + {file = "threadpoolctl-3.4.0-py3-none-any.whl", hash = "sha256:8f4c689a65b23e5ed825c8436a92b818aac005e0f3715f6a1664d7c7ee29d262"}, + {file = "threadpoolctl-3.4.0.tar.gz", hash = "sha256:f11b491a03661d6dd7ef692dd422ab34185d982466c49c8f98c8f716b5c93196"}, +] + [[package]] name = "tinycss2" version = "1.2.1" @@ -4961,17 +4939,6 @@ webencodings = ">=0.4" doc = ["sphinx", "sphinx_rtd_theme"] test = ["flake8", "isort", "pytest"] -[[package]] -name = "threadpoolctl" -version = "3.4.0" -description = "threadpoolctl" -optional = false -python-versions = ">=3.8" -files = [ - {file = "threadpoolctl-3.4.0-py3-none-any.whl", hash = "sha256:8f4c689a65b23e5ed825c8436a92b818aac005e0f3715f6a1664d7c7ee29d262"}, - {file = "threadpoolctl-3.4.0.tar.gz", hash = "sha256:f11b491a03661d6dd7ef692dd422ab34185d982466c49c8f98c8f716b5c93196"}, -] - [[package]] name = "toml" version = "0.10.2" @@ -5047,18 +5014,18 @@ telegram = ["requests"] [[package]] name = "traitlets" -version = "5.14.1" +version = "5.14.2" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, - {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, + {file = "traitlets-5.14.2-py3-none-any.whl", hash = "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"}, + {file = "traitlets-5.14.2.tar.gz", hash = "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.1)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "typeguard" @@ -5100,13 +5067,13 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.10.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -5157,6 +5124,21 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "waitress" +version = "3.0.0" +description = "Waitress WSGI server" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"}, + {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, +] + +[package.extras] +docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] +testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] + [[package]] name = "wcwidth" version = "0.2.13" @@ -5179,21 +5161,6 @@ files = [ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] -[[package]] -name = "waitress" -version = "3.0.0" -description = "Waitress WSGI server" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"}, - {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, -] - -[package.extras] -docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] -testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] - [[package]] name = "werkzeug" version = "3.0.2" @@ -5251,16 +5218,6 @@ files = [ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecee4132c6cd2ce5308e21672015ddfed1ff975ad0ac8d27168ea82e71413f55"}, - {file = "wrapt-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2020f391008ef874c6d9e208b24f28e31bcb85ccff4f335f15a3251d222b92d9"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2feecf86e1f7a86517cab34ae6c2f081fd2d0dac860cb0c0ded96d799d20b335"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:240b1686f38ae665d1b15475966fe0472f78e71b1b4903c143a842659c8e4cb9"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9008dad07d71f68487c91e96579c8567c98ca4c3881b9b113bc7b33e9fd78b8"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6447e9f3ba72f8e2b985a1da758767698efa72723d5b59accefd716e9e8272bf"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acae32e13a4153809db37405f5eba5bac5fbe2e2ba61ab227926a22901051c0a"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49ef582b7a1152ae2766557f0550a9fcbf7bbd76f43fbdc94dd3bf07cc7168be"}, - {file = "wrapt-1.14.1-cp311-cp311-win32.whl", hash = "sha256:358fe87cc899c6bb0ddc185bf3dbfa4ba646f05b1b0b9b5a27c2cb92c2cea204"}, - {file = "wrapt-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:26046cd03936ae745a502abf44dac702a5e6880b2b01c29aea8ddf3353b68224"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, @@ -5347,4 +5304,4 @@ dask = ["dask[array] (>=2022.11.1,<2023.0.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "d88397c8574c5a6b83d69853465c74e110fcaeeccec099861841fda2ad539547" +content-hash = "e653af1e109d3da222e17f50a2519e9775c7392e5114dab48bffbb83bf5c58df" From 286f80e8932c2377e622ef66cb0d6599ea16dd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 15:58:08 +0200 Subject: [PATCH 161/192] properly added mlflow dependency --- poetry.lock | 1436 +++++++++++++++++++++++++++++++++++++++++------- pyproject.toml | 6 +- 2 files changed, 1246 insertions(+), 196 deletions(-) diff --git a/poetry.lock b/poetry.lock index be1a69da..7327a27e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "absl-py" @@ -142,10 +142,57 @@ description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] +[[package]] +name = "alembic" +version = "1.13.1" +description = "A database migration tool for SQLAlchemy." +optional = false +python-versions = ">=3.8" +files = [ + {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, + {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, +] + +[package.dependencies] +Mako = "*" +SQLAlchemy = ">=1.3.0" +typing-extensions = ">=4" + +[package.extras] +tz = ["backports.zoneinfo"] + +[[package]] +name = "amqp" +version = "5.2.0" +description = "Low-level AMQP client for Python (fork of amqplib)." +optional = true +python-versions = ">=3.6" +files = [ + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, +] + +[package.dependencies] +vine = ">=5.0.0,<6.0.0" + +[[package]] +name = "aniso8601" +version = "9.0.1" +description = "A library for parsing ISO 8601 strings." +optional = false +python-versions = "*" +files = [ + {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"}, + {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"}, +] + +[package.extras] +dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] + [[package]] name = "annotated-types" version = "0.6.0" @@ -237,23 +284,70 @@ files = [ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = true +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "asyncssh" +version = "2.14.2" +description = "AsyncSSH: Asynchronous SSHv2 client and server library" +optional = true +python-versions = ">= 3.6" +files = [ + {file = "asyncssh-2.14.2-py3-none-any.whl", hash = "sha256:6ff9923389a16bda4f681c1fc253386cc4e1f19fb74fd0684dd0d31943ebe5e4"}, + {file = "asyncssh-2.14.2.tar.gz", hash = "sha256:e956bf8988d07a06ba3305f6604e261f4ca014c4a232f0873f1c7692fbe3cfc2"}, +] + +[package.dependencies] +cryptography = ">=39.0" +typing-extensions = ">=3.6" + +[package.extras] +bcrypt = ["bcrypt (>=3.1.3)"] +fido2 = ["fido2 (>=0.9.2)"] +gssapi = ["gssapi (>=1.2.0)"] +libnacl = ["libnacl (>=1.4.2)"] +pkcs11 = ["python-pkcs11 (>=0.7.0)"] +pyopenssl = ["pyOpenSSL (>=23.0.0)"] +pywin32 = ["pywin32 (>=227)"] + +[[package]] +name = "atpublic" +version = "4.1.0" +description = "Keep all y'all's __all__'s in sync" +optional = true +python-versions = ">=3.8" +files = [ + {file = "atpublic-4.1.0-py3-none-any.whl", hash = "sha256:df90de1162b1a941ee486f484691dc7c33123ee638ea5d6ca604061306e0fdde"}, + {file = "atpublic-4.1.0.tar.gz", hash = "sha256:d1c8cd931af7461f6d18bc6063383e8654d9e9ef19d58ee6dc01e8515bbf55df"}, +] + [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" -optional = false +optional = true python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "babel" @@ -659,6 +753,66 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "click-didyoumean" +version = "0.3.1" +description = "Enables git-like *did-you-mean* feature in click" +optional = true +python-versions = ">=3.6.2" +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] + +[package.dependencies] +click = ">=7" + +[[package]] +name = "click-plugins" +version = "1.1.1" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = true +python-versions = "*" +files = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = true +python-versions = ">=3.6" +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + +[[package]] +name = "cloudpickle" +version = "3.0.0" +description = "Pickler class to extend the standard pickle.Pickler functionality" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"}, + {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"}, +] + [[package]] name = "clu" version = "0.0.7" @@ -935,14 +1089,31 @@ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] -name = "dataclasses" -version = "0.6" -description = "A backport of the dataclasses module for Python 3.6" -optional = false +name = "dictdiffer" +version = "0.9.0" +description = "Dictdiffer is a library that helps you to diff and patch dictionaries." +optional = true python-versions = "*" files = [ - {file = "dataclasses-0.6-py3-none-any.whl", hash = "sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f"}, - {file = "dataclasses-0.6.tar.gz", hash = "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"}, + {file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"}, + {file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"}, +] + +[package.extras] +all = ["Sphinx (>=3)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "tox (>=3.7.0)"] +docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"] +numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"] +tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "tox (>=3.7.0)"] + +[[package]] +name = "diskcache" +version = "5.6.3" +description = "Disk Cache -- Disk and file backed persistent cache." +optional = true +python-versions = ">=3" +files = [ + {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, + {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, ] [[package]] @@ -957,26 +1128,16 @@ files = [ ] [[package]] -name = "dm-haiku" -version = "0.0.11" -description = "Haiku is a library for building neural networks in JAX." -optional = false -python-versions = "*" +name = "distro" +version = "1.9.0" +description = "Distro - an OS platform information API" +optional = true +python-versions = ">=3.6" files = [ - {file = "dm-haiku-0.0.11.tar.gz", hash = "sha256:c420a90c6a76c1d941996698840089df0d352806312eaf7b737486f6c6a32ef2"}, - {file = "dm_haiku-0.0.11-py3-none-any.whl", hash = "sha256:4cac556a9d0e41758abda66bef5ff9dbb36e409c8cfc2b6f20247bc7d39ae45b"}, + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, ] -[package.dependencies] -absl-py = ">=0.7.1" -flax = ">=0.7.1" -jmp = ">=0.0.2" -numpy = ">=1.18.0" -tabulate = ">=0.8.9" - -[package.extras] -jax = ["jax (>=0.4.16)", "jaxlib (>=0.4.16)"] - [[package]] name = "dm-tree" version = "0.1.8" @@ -1001,13 +1162,6 @@ files = [ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa42a605d099ee7d41ba2b5fb75e21423951fd26e5d50583a00471238fb3021d"}, {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b7764de0d855338abefc6e3ee9fe40d301668310aa3baea3f778ff051f4393"}, {file = "dm_tree-0.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:a5d819c38c03f0bb5b3b3703c60e4b170355a0fc6b5819325bf3d4ceb3ae7e80"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea9e59e0451e7d29aece402d9f908f2e2a80922bcde2ebfd5dcb07750fcbfee8"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:94d3f0826311f45ee19b75f5b48c99466e4218a0489e81c0f0167bda50cacf22"}, - {file = "dm_tree-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:435227cf3c5dc63f4de054cf3d00183790bd9ead4c3623138c74dde7f67f521b"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09964470f76a5201aff2e8f9b26842976de7889300676f927930f6285e256760"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75c5d528bb992981c20793b6b453e91560784215dffb8a5440ba999753c14ceb"}, - {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a94aba18a35457a1b5cd716fd7b46c5dafdc4cf7869b4bae665b91c4682a8e"}, - {file = "dm_tree-0.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:96a548a406a6fb15fe58f6a30a57ff2f2aafbf25f05afab00c8f5e5977b6c715"}, {file = "dm_tree-0.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8c60a7eadab64c2278861f56bca320b2720f163dca9d7558103c3b77f2416571"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af4b3d372f2477dcd89a6e717e4a575ca35ccc20cc4454a8a4b6f8838a00672d"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de287fabc464b8734be251e46e06aa9aa1001f34198da2b6ce07bd197172b9cb"}, @@ -1065,25 +1219,313 @@ files = [ ] [[package]] -name = "e3nn-jax" -version = "0.20.4" -description = "Equivariant convolutional neural networks for the group E(3) of 3 dimensional rotations, translations, and mirrors." -optional = false +name = "dot4dict" +version = "0.1.1" +description = "A Python Package to enable dot-notation on dictionaries" +optional = true +python-versions = ">=3.7" +files = [ + {file = "dot4dict-0.1.1-py3-none-any.whl", hash = "sha256:40fa529924f1694bb797a00b586019a28903e4445fd22e4652c09d12c0b28299"}, + {file = "dot4dict-0.1.1.tar.gz", hash = "sha256:3b0f05b0a0e03832db32a191b7bcd52cff45dd53a354b8d75da3f94ed152b712"}, +] + +[[package]] +name = "dpath" +version = "2.1.6" +description = "Filesystem-like pathing and searching for dictionaries" +optional = true +python-versions = ">=3.7" +files = [ + {file = "dpath-2.1.6-py3-none-any.whl", hash = "sha256:31407395b177ab63ef72e2f6ae268c15e938f2990a8ecf6510f5686c02b6db73"}, + {file = "dpath-2.1.6.tar.gz", hash = "sha256:f1e07c72e8605c6a9e80b64bc8f42714de08a789c7de417e49c3f87a19692e47"}, +] + +[[package]] +name = "dulwich" +version = "0.21.7" +description = "Python Git Library" +optional = true +python-versions = ">=3.7" +files = [ + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c"}, + {file = "dulwich-0.21.7-cp310-cp310-win32.whl", hash = "sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08"}, + {file = "dulwich-0.21.7-cp310-cp310-win_amd64.whl", hash = "sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1"}, + {file = "dulwich-0.21.7-cp311-cp311-win32.whl", hash = "sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde"}, + {file = "dulwich-0.21.7-cp311-cp311-win_amd64.whl", hash = "sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91"}, + {file = "dulwich-0.21.7-cp312-cp312-win32.whl", hash = "sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec"}, + {file = "dulwich-0.21.7-cp312-cp312-win_amd64.whl", hash = "sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503"}, + {file = "dulwich-0.21.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a"}, + {file = "dulwich-0.21.7-cp37-cp37m-win32.whl", hash = "sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9"}, + {file = "dulwich-0.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041"}, + {file = "dulwich-0.21.7-cp38-cp38-win32.whl", hash = "sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b"}, + {file = "dulwich-0.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed"}, + {file = "dulwich-0.21.7-cp39-cp39-win32.whl", hash = "sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1"}, + {file = "dulwich-0.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31"}, + {file = "dulwich-0.21.7.tar.gz", hash = "sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968"}, +] + +[package.dependencies] +urllib3 = ">=1.25" + +[package.extras] +fastimport = ["fastimport"] +https = ["urllib3 (>=1.24.1)"] +paramiko = ["paramiko"] +pgp = ["gpg"] + +[[package]] +name = "dvc" +version = "3.49.0" +description = "Git for data scientists - manage your code and data together" +optional = true python-versions = ">=3.9" files = [ - {file = "e3nn-jax-0.20.4.tar.gz", hash = "sha256:3dab5099d845c44050ad7cdeb71434df15f42f8946c05f44e2ede37f0120e797"}, - {file = "e3nn_jax-0.20.4-py3-none-any.whl", hash = "sha256:839b4664ce4a09228fd264ad9cbfe879adc591faa4534ae747962dafd04c6607"}, + {file = "dvc-3.49.0-py3-none-any.whl", hash = "sha256:5122424debe4a4192cdae76918df4194153e61c7fa9224c0d82627d2786110c7"}, + {file = "dvc-3.49.0.tar.gz", hash = "sha256:ab3779ef9a422e0a6734765a98f05cadaab7290de8726db023e0c14ec079031f"}, ] [package.dependencies] -attrs = "*" -jax = "*" -jaxlib = "*" -numpy = "*" -sympy = "*" +attrs = ">=22.2.0" +celery = "*" +colorama = ">=0.3.9" +configobj = ">=5.0.6" +distro = ">=1.3" +dpath = ">=2.1.0,<3" +dulwich = "*" +dvc-data = ">=3.15,<3.16" +dvc-http = ">=2.29.0" +dvc-objects = "*" +dvc-render = ">=1.0.1,<2" +dvc-studio-client = ">=0.20,<1" +dvc-task = ">=0.3.0,<1" +flatten-dict = ">=0.4.1,<1" +"flufl.lock" = ">=5,<8" +fsspec = "*" +funcy = ">=1.14" +grandalf = ">=0.7,<1" +gto = ">=1.6.0,<2" +hydra-core = ">=1.1" +iterative-telemetry = ">=0.0.7" +kombu = "*" +networkx = ">=2.5" +omegaconf = "*" +packaging = ">=19" +pathspec = ">=0.10.3" +platformdirs = ">=3.1.1,<4" +psutil = ">=5.8" +pydot = ">=1.2.4" +pygtrie = ">=2.3.2" +pyparsing = ">=2.4.7" +requests = ">=2.22" +rich = ">=12" +"ruamel.yaml" = ">=0.17.11" +scmrepo = ">=3,<4" +shortuuid = ">=0.5" +shtab = ">=1.3.4,<2" +tabulate = ">=0.8.7" +tomlkit = ">=0.11.1" +tqdm = ">=4.63.1,<5" +voluptuous = ">=0.11.7" +"zc.lockfile" = ">=1.2.1" + +[package.extras] +all = ["dvc[azure,gdrive,gs,hdfs,oss,s3,ssh,webdav,webhdfs]"] +azure = ["dvc-azure (>=3.1.0,<4)"] +dev = ["dvc[azure,gdrive,gs,hdfs,lint,oss,s3,ssh,tests,webdav,webhdfs]"] +gdrive = ["dvc-gdrive (>=3,<4)"] +gs = ["dvc-gs (>=3,<4)"] +hdfs = ["dvc-hdfs (>=3,<4)"] +lint = ["mypy (==1.9.0)", "pandas-stubs", "types-colorama", "types-psutil", "types-pyinstaller", "types-requests", "types-tabulate", "types-toml", "types-tqdm", "typing-extensions"] +oss = ["dvc-oss (>=3,<4)"] +s3 = ["dvc-s3 (>=3,<4)"] +ssh = ["dvc-ssh (>=4,<5)"] +ssh-gssapi = ["dvc-ssh[gssapi] (>=4,<5)"] +testing = ["pytest-benchmark[histogram]", "pytest-test-utils", "virtualenv"] +tests = ["beautifulsoup4 (>=4.4)", "dvc-ssh", "dvc[testing]", "filelock", "pandas (>=1)", "pytest (>=7,<9)", "pytest-cov (>=4.1.0)", "pytest-docker (>=1,<4)", "pytest-mock", "pytest-rerunfailures", "pytest-test-utils", "pytest-timeout (>=2)", "pytest-xdist (>=3.2)", "pywin32 (>=225)", "sqlalchemy (>=1,<3)", "tzdata"] +webdav = ["dvc-webdav (>=3,<4)"] +webhdfs = ["dvc-webhdfs (>=3.1,<4)"] +webhdfs-kerberos = ["dvc-webhdfs[kerberos] (>=3.1,<4)"] + +[[package]] +name = "dvc-data" +version = "3.15.1" +description = "DVC's data management subsystem" +optional = true +python-versions = ">=3.9" +files = [ + {file = "dvc-data-3.15.1.tar.gz", hash = "sha256:db141bbbcf9e1ff37d9ff8657d04747e804899b90b4931b120f5d21bbd401583"}, + {file = "dvc_data-3.15.1-py3-none-any.whl", hash = "sha256:e869825af922add091bc3e2de477ba0d05e847db402bb4044483600161f3a7a7"}, +] + +[package.dependencies] +attrs = ">=21.3.0" +dictdiffer = ">=0.8.1" +diskcache = ">=5.2.1" +dvc-objects = ">=4.0.1,<6" +fsspec = ">=2024.2.0" +funcy = {version = ">=1.14", markers = "python_version < \"3.12\""} +pygtrie = ">=2.3.2" +sqltrie = ">=0.11.0,<1" +tqdm = ">=4.63.1,<5" + +[package.extras] +all = ["dvc-data[cli]"] +cli = ["rich (>=10.11.0,<14.0.0)", "typer[all] (>=0.6)"] +dev = ["blake3 (>=0.3.1)", "dvc-data[all]", "dvc-data[tests]", "mypy (==1.9.0)", "types-tqdm"] +tests = ["pytest (>=7,<9)", "pytest-benchmark (>=4)", "pytest-cov (>=4.1.0)", "pytest-mock", "pytest-servers[s3] (==0.5.0)", "pytest-sugar"] + +[[package]] +name = "dvc-http" +version = "2.32.0" +description = "http plugin for dvc" +optional = true +python-versions = ">=3.8" +files = [ + {file = "dvc-http-2.32.0.tar.gz", hash = "sha256:f714f8435634aab943c625f659ddac1188c6ddaf3ff161b39715b83ff39637fc"}, + {file = "dvc_http-2.32.0-py3-none-any.whl", hash = "sha256:1bfd57a9eae3cbfa1db564d90d87003841921a644ab35f3f7735c641cc93d72e"}, +] + +[package.dependencies] +aiohttp-retry = ">=2.5.0" +fsspec = {version = "*", extras = ["http"]} + +[package.extras] +tests = ["dvc[testing]", "flaky (==3.7.0)", "mypy (==0.910)", "pylint (==2.15.9)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)", "pytest-mock (==3.6.1)", "pytest-xdist (==2.4.0)", "rangehttpserver (==1.2.0)", "types-requests (==2.25.11)"] + +[[package]] +name = "dvc-objects" +version = "5.1.0" +description = "dvc objects - filesystem and object-db level abstractions to use in dvc and dvc-data" +optional = true +python-versions = ">=3.9" +files = [ + {file = "dvc-objects-5.1.0.tar.gz", hash = "sha256:22e919620f9ecf428a0d295efca8073d1c0e87206dd8e1f52b1d9520fa25b814"}, + {file = "dvc_objects-5.1.0-py3-none-any.whl", hash = "sha256:c29b28f372674f53eca13323832d7b61c14bc29d516c39f6e87c5eba871a00ba"}, +] + +[package.dependencies] +fsspec = ">=2024.2.0" +funcy = {version = ">=1.14", markers = "python_version < \"3.12\""} + +[package.extras] +dev = ["dvc-objects[tests]", "mypy (==1.8.0)"] +tests = ["pytest (>=7,<8)", "pytest-asyncio (>=0.23.2,<1)", "pytest-benchmark", "pytest-cov (>=4.1.0)", "pytest-mock", "pytest-sugar", "reflink"] + +[[package]] +name = "dvc-render" +version = "1.0.1" +description = "Dvc Render" +optional = true +python-versions = ">=3.8" +files = [ + {file = "dvc-render-1.0.1.tar.gz", hash = "sha256:d7296869ea64c18ead9c99c46062ff116503b77a8d6e5c988f2d24716ea01d4a"}, + {file = "dvc_render-1.0.1-py3-none-any.whl", hash = "sha256:a8704e2048cd698d5ee19a611619f4f0e9c0a8508a2af3652198a2cb79b7a279"}, +] [package.extras] -dev = ["dm-haiku", "flax", "jraph", "kaleido", "nox", "optax", "plotly", "pytest", "s2fft", "tqdm"] +dev = ["dvc-render[docs]", "dvc-render[markdown]", "dvc-render[table]", "dvc-render[tests]"] +docs = ["mkdocs (==1.5.2)", "mkdocs-gen-files (==0.5.0)", "mkdocs-material (==9.3.1)", "mkdocs-section-index (==0.3.6)", "mkdocstrings-python (==1.6.3)"] +markdown = ["dvc-render[table]", "matplotlib"] +table = ["flatten-dict (>=0.4.1,<1)", "tabulate (>=0.8.7)"] +tests = ["dvc-render[markdown]", "dvc-render[table]", "mypy (==1.2.0)", "pytest (==7.2.0)", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.7)"] + +[[package]] +name = "dvc-studio-client" +version = "0.20.0" +description = "Small library to post data from DVC/DVCLive to Iterative Studio" +optional = true +python-versions = ">=3.8" +files = [ + {file = "dvc-studio-client-0.20.0.tar.gz", hash = "sha256:a242e9c46297c689d65ff28d439b7c2e7535b641f09860f871b5628f7ae4bc42"}, + {file = "dvc_studio_client-0.20.0-py3-none-any.whl", hash = "sha256:b9ee7c419a799ecdaeaf872114e6d664be1584822473fdf8aff43c961a3e2aa3"}, +] + +[package.dependencies] +dulwich = "*" +requests = "*" +voluptuous = "*" + +[package.extras] +dev = ["dvc-studio-client[docs]", "dvc-studio-client[tests]", "types-requests"] +docs = ["mkdocs (==1.5.3)", "mkdocs-gen-files (==0.5.0)", "mkdocs-material (==9.5.8)", "mkdocs-section-index (==0.3.8)", "mkdocstrings-python (==1.8.0)"] +tests = ["mypy (==1.8.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-mock (==3.12.0)", "pytest-sugar (==1.0.0)"] + +[[package]] +name = "dvc-task" +version = "0.4.0" +description = "Extensible task queue used in DVC." +optional = true +python-versions = ">=3.8" +files = [ + {file = "dvc-task-0.4.0.tar.gz", hash = "sha256:c0166626af9c0e932ba18194fbc57df38f22860fcc0fbd450dee14ef9615cd3c"}, + {file = "dvc_task-0.4.0-py3-none-any.whl", hash = "sha256:ed047e4bb5031fcf640357ae4638a2a89e34f556560ed9d1fbf6646ed4e8cca6"}, +] + +[package.dependencies] +celery = ">=5.3.0,<6" +funcy = ">=1.17" +kombu = ">=5.3.0,<6" +pywin32 = {version = ">=225", markers = "sys_platform == \"win32\""} +shortuuid = ">=1.0.8" + +[package.extras] +dev = ["celery-types", "celery-types (==0.15.0)", "dvc-task[docs,tests]", "mypy (==1.9.0)"] +docs = ["mkdocs (>=1.5.2,<2)", "mkdocs-gen-files (>=0.5.0,<1)", "mkdocs-material (>=9.3.1,<10)", "mkdocs-section-index (>=0.3.6,<1)", "mkdocstrings-python (>=1.6.3,<2)"] +tests = ["pytest (>=7,<9)", "pytest-celery", "pytest-cov (>=4.1.0)", "pytest-mock", "pytest-rerunfailures", "pytest-sugar", "pytest-test-utils (>=0.0.6)"] [[package]] name = "einops" @@ -1096,6 +1538,17 @@ files = [ {file = "einops-0.6.1.tar.gz", hash = "sha256:f95f8d00f4ded90dbc4b19b6f98b177332614b0357dde66997f3ae5d474dc8c8"}, ] +[[package]] +name = "entrypoints" +version = "0.4" +description = "Discover and load entry points from installed packages." +optional = false +python-versions = ">=3.6" +files = [ + {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, + {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, +] + [[package]] name = "etils" version = "1.7.0" @@ -1108,11 +1561,9 @@ files = [ ] [package.dependencies] -absl-py = {version = "*", optional = true, markers = "extra == \"etqdm\""} fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} numpy = {version = "*", optional = true, markers = "extra == \"enp\""} -tqdm = {version = "*", optional = true, markers = "extra == \"etqdm\""} typing_extensions = {version = "*", optional = true, markers = "extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} @@ -1270,7 +1721,22 @@ typing-extensions = ">=4.2" [package.extras] all = ["matplotlib"] -testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9)", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "nbstripout", "opencv-python", "pytest", "pytest-cov", "pytest-custom-exit-code", "pytest-xdist (==1.34.0)", "pytype", "sentencepiece", "tensorflow", "tensorflow-datasets", "tensorflow-text (>=2.11.0)", "torch"] +testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9)", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "nbstripout", "opencv-python", "pytest", "pytest-cov", "pytest-custom-exit-code", "pytest-xdist", "pytype", "sentencepiece", "tensorflow", "tensorflow-datasets", "tensorflow-text (>=2.11.0)", "torch"] + +[[package]] +name = "flufl-lock" +version = "7.1.1" +description = "NFS-safe file locking with timeouts for POSIX and Windows" +optional = true +python-versions = ">=3.7" +files = [ + {file = "flufl.lock-7.1.1-py3-none-any.whl", hash = "sha256:96d2c0448ba9fd8fc65d5d681ed7217c8e1625149c1c880bba50559bb680a615"}, + {file = "flufl.lock-7.1.1.tar.gz", hash = "sha256:af14172b35bbc58687bd06b70d1693fd8d48cbf0ffde7e51a618c148ae24042d"}, +] + +[package.dependencies] +atpublic = ">=2.3" +psutil = ">=5.9.0" [[package]] name = "fonttools" @@ -1501,6 +1967,38 @@ files = [ {file = "gast-0.5.4.tar.gz", hash = "sha256:9c270fe5f4b130969b54174de7db4e764b09b4f7f67ccfc32480e29f78348d97"}, ] +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.43" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] + [[package]] name = "google-auth" version = "2.29.0" @@ -1574,6 +2072,139 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4 [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +[[package]] +name = "grandalf" +version = "0.8" +description = "Graph and drawing algorithms framework" +optional = true +python-versions = "*" +files = [ + {file = "grandalf-0.8-py3-none-any.whl", hash = "sha256:793ca254442f4a79252ea9ff1ab998e852c1e071b863593e5383afee906b4185"}, + {file = "grandalf-0.8.tar.gz", hash = "sha256:2813f7aab87f0d20f334a3162ccfbcbf085977134a17a5b516940a93a77ea974"}, +] + +[package.dependencies] +pyparsing = "*" + +[package.extras] +full = ["numpy", "ply"] + +[[package]] +name = "graphene" +version = "3.3" +description = "GraphQL Framework for Python" +optional = false +python-versions = "*" +files = [ + {file = "graphene-3.3-py2.py3-none-any.whl", hash = "sha256:bb3810be33b54cb3e6969506671eb72319e8d7ba0d5ca9c8066472f75bf35a38"}, + {file = "graphene-3.3.tar.gz", hash = "sha256:529bf40c2a698954217d3713c6041d69d3f719ad0080857d7ee31327112446b0"}, +] + +[package.dependencies] +aniso8601 = ">=8,<10" +graphql-core = ">=3.1,<3.3" +graphql-relay = ">=3.1,<3.3" + +[package.extras] +dev = ["black (==22.3.0)", "coveralls (>=3.3,<4)", "flake8 (>=4,<5)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"] +test = ["coveralls (>=3.3,<4)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"] + +[[package]] +name = "graphql-core" +version = "3.2.3" +description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, + {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, +] + +[[package]] +name = "graphql-relay" +version = "3.2.0" +description = "Relay library for graphql-core" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"}, + {file = "graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"}, +] + +[package.dependencies] +graphql-core = ">=3.2,<3.3" + +[[package]] +name = "greenlet" +version = "3.0.3" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + [[package]] name = "grpcio" version = "1.62.1" @@ -1638,7 +2269,52 @@ files = [ ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.62.1)"] + +[[package]] +name = "gto" +version = "1.7.1" +description = "Version and deploy your models following GitOps principles" +optional = true +python-versions = ">=3.9" +files = [ + {file = "gto-1.7.1-py3-none-any.whl", hash = "sha256:466c3e059aacc7eb3b7780a5f4b49e4a32001b059feb2b426d5b0737f7e71f72"}, + {file = "gto-1.7.1.tar.gz", hash = "sha256:24100e735195c0d54539401f42804fc9042998276cdc4233f49f153fd38a7d75"}, +] + +[package.dependencies] +entrypoints = "*" +funcy = "*" +pydantic = ">=1.9.0,<2.0.0 || >2.0.0,<3" +rich = "*" +"ruamel.yaml" = "*" +scmrepo = ">=3,<4" +semver = ">=2.13.0" +tabulate = ">=0.8.10" +typer = ">=0.4.1" + +[package.extras] +tests = ["freezegun", "pylint (==3.1.0)", "pylint-plugin-utils", "pytest", "pytest-cov", "pytest-mock", "pytest-test-utils", "types-freezegun"] + +[[package]] +name = "gunicorn" +version = "21.2.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.5" +files = [ + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] [[package]] name = "h5py" @@ -1788,15 +2464,47 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] +[[package]] +name = "iterative-telemetry" +version = "0.0.8" +description = "Common library for sending telemetry" +optional = true +python-versions = ">=3.8" +files = [ + {file = "iterative-telemetry-0.0.8.tar.gz", hash = "sha256:5bed9d19109c892cff2a4712a2fb18ad727079a7ab260a28b1e2f6934eec652d"}, + {file = "iterative_telemetry-0.0.8-py3-none-any.whl", hash = "sha256:af0a37ec727c1fd728df6e8103e4c89557b99869218e668dce5ca99e6e51231f"}, +] + +[package.dependencies] +appdirs = "*" +distro = "*" +filelock = "*" +requests = "*" + +[package.extras] +dev = ["mypy (==0.971)", "pylint (==2.15.0)", "pytest (==7.2.0)", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.5)", "types-requests"] +tests = ["mypy (==0.971)", "pylint (==2.15.0)", "pytest (==7.2.0)", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.5)", "types-requests"] + +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +optional = false +python-versions = ">=3.7" +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] + [[package]] name = "jax" -version = "0.4.25" +version = "0.4.26" description = "Differentiate, compile, and transform Numpy code." optional = false python-versions = ">=3.9" files = [ - {file = "jax-0.4.25-py3-none-any.whl", hash = "sha256:8158c837e5ecc195074b421609e85329a962785b36f9fe5ff53e844e8ad87dbc"}, - {file = "jax-0.4.25.tar.gz", hash = "sha256:a8ee189c782de2b7b2ffb64a8916da380b882a617e2769aa429b71d79747b982"}, + {file = "jax-0.4.26-py3-none-any.whl", hash = "sha256:50dc795148ee6b0735b48b477e5abc556aa3a4c7af5d6940dad08024a908b02f"}, + {file = "jax-0.4.26.tar.gz", hash = "sha256:2cce025d0a279ec630d550524749bc8efe25d2ff47240d2a7d4cfbc5090c5383"}, ] [package.dependencies] @@ -1810,45 +2518,43 @@ scipy = ">=1.9" [package.extras] australis = ["protobuf (>=3.13,<4)"] -ci = ["jaxlib (==0.4.24)"] -cpu = ["jaxlib (==0.4.25)"] -cuda = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-cudnn86 = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-local = ["jaxlib (==0.4.25+cuda11.cudnn86)"] -cuda11-pip = ["jaxlib (==0.4.25+cuda11.cudnn86)", "nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)", "nvidia-nccl-cu11 (>=2.18.3)"] -cuda12 = ["jax-cuda12-plugin (==0.4.25)", "jaxlib (==0.4.25)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] -cuda12-local = ["jaxlib (==0.4.25+cuda12.cudnn89)"] -cuda12-pip = ["jaxlib (==0.4.25+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.3.4.1)", "nvidia-cuda-cupti-cu12 (>=12.3.101)", "nvidia-cuda-nvcc-cu12 (>=12.3.107)", "nvidia-cuda-runtime-cu12 (>=12.3.101)", "nvidia-cudnn-cu12 (>=8.9.7.29)", "nvidia-cufft-cu12 (>=11.0.12.1)", "nvidia-cusolver-cu12 (>=11.5.4.101)", "nvidia-cusparse-cu12 (>=12.2.0.103)", "nvidia-nccl-cu12 (>=2.19.3)", "nvidia-nvjitlink-cu12 (>=12.3.101)"] +ci = ["jaxlib (==0.4.25)"] +cpu = ["jaxlib (==0.4.26)"] +cuda = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12 = ["jax-cuda12-plugin (==0.4.26)", "jaxlib (==0.4.26)", "nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] +cuda12-cudnn89 = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12-local = ["jaxlib (==0.4.26+cuda12.cudnn89)"] +cuda12-pip = ["jaxlib (==0.4.26+cuda12.cudnn89)", "nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] minimum-jaxlib = ["jaxlib (==0.4.20)"] -tpu = ["jaxlib (==0.4.25)", "libtpu-nightly (==0.1.dev20240224)", "requests"] +tpu = ["jaxlib (==0.4.26)", "libtpu-nightly (==0.1.dev20240403)", "requests"] [[package]] name = "jaxlib" -version = "0.4.25" +version = "0.4.26" description = "XLA library for JAX" optional = false python-versions = ">=3.9" files = [ - {file = "jaxlib-0.4.25-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:be1b26e96e80d42f54f77226a016717cb969d7d208d0dcb61997f19dc7b2d8e2"}, - {file = "jaxlib-0.4.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3b5cbd3a4f731636469cdaf06c4413208811ca458ee312647e8f3faca32f6445"}, - {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:89a011330aaeaf19027bba5e3236be155cc8d73d94aa9db84d817d414f4a7647"}, - {file = "jaxlib-0.4.25-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:dcda74c7c8eb328cde8afeebcf21ec9240138fac54f9631a60b679a211f7e100"}, - {file = "jaxlib-0.4.25-cp310-cp310-win_amd64.whl", hash = "sha256:fd751b10e60c085dec42bec6c27c9905f5c57d12323190eea0df10ee14c574e0"}, - {file = "jaxlib-0.4.25-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:37da780cb545ca210bfa0402b5081452ad830bb06fe9e970fd16ad14d2fdc6a6"}, - {file = "jaxlib-0.4.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df7e2193b216e195dfc7a8aa14527eb52614ec3ba4c59a199af2f17195ae1c1"}, - {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:0ce2a25263e7504d575e8ba5ba4f53aef6fe274679785bcf87ab06b0aaec0b90"}, - {file = "jaxlib-0.4.25-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:a0dd09cbb62583941872b6a198894e87a1b64d8e4dd6b53946dbb41d642b8f5f"}, - {file = "jaxlib-0.4.25-cp311-cp311-win_amd64.whl", hash = "sha256:dfb1ef8c2e6a01ecb60f8833552ff077cd593154fd75739050fba9148879a2a4"}, - {file = "jaxlib-0.4.25-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:425d6f3fa57ea1d1674ae84b5a3d3588ba0937f3c47fd4f166eb84c4240887b8"}, - {file = "jaxlib-0.4.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e97542bbd89f4316d2feb599119d8a43440ca151b7a165eff0fc127cf4512e7"}, - {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:c4e3bc32aea275e025e762612216954626478c9cf5c44131e248cdd17e361efd"}, - {file = "jaxlib-0.4.25-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:dcfb71a7f559c13734584769ca30373bc4b73d0fe105790462370e49f35dcbe4"}, - {file = "jaxlib-0.4.25-cp312-cp312-win_amd64.whl", hash = "sha256:f7aa9682b6806e4197ad51294e87e77f04f5eee7ced4e841aa7ccc7320c6d96b"}, - {file = "jaxlib-0.4.25-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:6660b68741286bd4b849c149d86a8c36e448f7e39e1d483e79dab79ea300bf1b"}, - {file = "jaxlib-0.4.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32881f93d5de195a0fd19e091a2aa89418fa27f630d30c79b4613a51cff4d1c6"}, - {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ad1ab653265c33b8d54bdcc40867a8ffd61fea879176e4d4cd0b585fe52521fc"}, - {file = "jaxlib-0.4.25-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:0fd113ab414de856f90f07264e6ccd0cb95d392f3579c0deab4ff0943ef75f73"}, - {file = "jaxlib-0.4.25-cp39-cp39-win_amd64.whl", hash = "sha256:b11aef2bd6cf873b39399fda122170b625776d977bbc56b4635f46c396279b8b"}, + {file = "jaxlib-0.4.26-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:f9060fd81d1b2a2c2069e998db2be04853c40a244ab9edb1caf1c5cbd2f70881"}, + {file = "jaxlib-0.4.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e61ded57e05764350f7065583d85ab9270e7f7ed6b9f9d9394fe6ff64d96aab7"}, + {file = "jaxlib-0.4.26-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d483aff58898bf37e341d6241cecb3e107aebe4ca237fe6267d4c18b7c09ea90"}, + {file = "jaxlib-0.4.26-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:22e943ed10faa7d85fd804ddc20581bf6fbcc60e114435c3b3327b9f1ebff895"}, + {file = "jaxlib-0.4.26-cp310-cp310-win_amd64.whl", hash = "sha256:eb0cc16efc6313eb100688a38078061caa3c907ebfa1d315485a08fd27f374dc"}, + {file = "jaxlib-0.4.26-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:de4b9a54cd96e6a732c1cf65ae2defdf6a01558a15db8bf6dbd8f40d363b085d"}, + {file = "jaxlib-0.4.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cbdcb95ac73f80ea3a82a53b8f0621f37dfb01ab0203de6fc6691a4e2396984"}, + {file = "jaxlib-0.4.26-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:6754ee0d4dd44f708c3826c51ce648c5e08cfc56cabf23d4f3b428971ab00094"}, + {file = "jaxlib-0.4.26-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:3069da7d75f5b4dd15350fffe6e6b86ca09c4b9fde60b10515edb09cef653335"}, + {file = "jaxlib-0.4.26-cp311-cp311-win_amd64.whl", hash = "sha256:516d2b573975bd666278badd650620d5edf3abb835978459d78f135e95419b04"}, + {file = "jaxlib-0.4.26-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:2c66fe8285fed13bcd44b7e10aa90a25a4a58af82450a4b18d0f1573c04a7797"}, + {file = "jaxlib-0.4.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9275761ae907ec0e812031bbae644f7a217e314e62d518c85d60ce686d3a3b0b"}, + {file = "jaxlib-0.4.26-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:597df919f00646d3f9c6feb2a39c9fa0fca00032f19cfe758916db3db30d416a"}, + {file = "jaxlib-0.4.26-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f084dd65f2b3cd804102d9cecf938d876cbbd54cb95308634020fc71b98fac79"}, + {file = "jaxlib-0.4.26-cp312-cp312-win_amd64.whl", hash = "sha256:72f117535d6dbc568adbcf6e1740037e0fe1d6e5b9558ea4158556005cf72bfc"}, + {file = "jaxlib-0.4.26-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0fea35b04cce0a6a758fd005132c02122dd49be5914d70c7d54e8eafdf3f352b"}, + {file = "jaxlib-0.4.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:520f71795c411b41cbea13488f1b17610780d7d9afc02ac5f9931a8c975780cb"}, + {file = "jaxlib-0.4.26-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d7bbb75f8e63c5ada57a386b7bfaac301f689149ba132509ccd0c865b2ebd4d2"}, + {file = "jaxlib-0.4.26-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:80b2440072da25d85634e98f755b8381781bd4c1ab4023b2ae0956c360124080"}, + {file = "jaxlib-0.4.26-cp39-cp39-win_amd64.whl", hash = "sha256:96c9a183d7a56572a5c1508de317a05badddfbbc8370a8fa8a2e548d5e059dc3"}, ] [package.dependencies] @@ -1857,8 +2563,7 @@ numpy = ">=1.22" scipy = ">=1.9" [package.extras] -cuda11-pip = ["nvidia-cublas-cu11 (>=11.11)", "nvidia-cuda-cupti-cu11 (>=11.8)", "nvidia-cuda-nvcc-cu11 (>=11.8)", "nvidia-cuda-runtime-cu11 (>=11.8)", "nvidia-cudnn-cu11 (>=8.8)", "nvidia-cufft-cu11 (>=10.9)", "nvidia-cusolver-cu11 (>=11.4)", "nvidia-cusparse-cu11 (>=11.7)"] -cuda12-pip = ["nvidia-cublas-cu12", "nvidia-cuda-cupti-cu12", "nvidia-cuda-nvcc-cu12", "nvidia-cuda-runtime-cu12", "nvidia-cudnn-cu12 (>=8.9)", "nvidia-cufft-cu12", "nvidia-cusolver-cu12", "nvidia-cusparse-cu12"] +cuda12-pip = ["nvidia-cublas-cu12 (>=12.1.3.1)", "nvidia-cuda-cupti-cu12 (>=12.1.105)", "nvidia-cuda-nvcc-cu12 (>=12.1.105)", "nvidia-cuda-runtime-cu12 (>=12.1.105)", "nvidia-cudnn-cu12 (>=8.9.2.26,<9.0)", "nvidia-cufft-cu12 (>=11.0.2.54)", "nvidia-cusolver-cu12 (>=11.4.5.107)", "nvidia-cusparse-cu12 (>=12.1.0.106)", "nvidia-nccl-cu12 (>=2.18.1)", "nvidia-nvjitlink-cu12 (>=12.1.105)"] [[package]] name = "jaxtyping" @@ -2081,19 +2786,47 @@ description = "Clang Python Bindings, mirrored from the official LLVM repo: http optional = false python-versions = "*" files = [ - {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:88bc7e7b393c32e41e03ba77ef02fdd647da1f764c2cd028e69e0837080b79f6"}, - {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:d80ed5827736ed5ec2bcedf536720476fd9d4fa4c79ef0cb24aea4c59332f361"}, - {file = "libclang-16.0.6-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:da9e47ebc3f0a6d90fb169ef25f9fbcd29b4a4ef97a8b0e3e3a17800af1423f4"}, - {file = "libclang-16.0.6-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1a5ad1e895e5443e205568c85c04b4608e4e973dae42f4dfd9cb46c81d1486b"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:9dcdc730939788b8b69ffd6d5d75fe5366e3ee007f1e36a99799ec0b0c001492"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:8130482120500476a027171f8f3c8dfc2536b591716eea71fc5da22cae13131b"}, - {file = "libclang-16.0.6-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:1e940048f51d0b0999099a9b78629ab8a64b62af5e9ff1b2b062439c21ee244d"}, - {file = "libclang-16.0.6-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f04e3060ae1f207f234d0608900c99c50edcb743e5e18276d78da2ddd727d39f"}, - {file = "libclang-16.0.6-py2.py3-none-win_amd64.whl", hash = "sha256:daab4a11dae228f1efa9efa3fe638b493b14d8d52c71fb3c7019e2f1df4514c2"}, - {file = "libclang-16.0.6-py2.py3-none-win_arm64.whl", hash = "sha256:4a9acbfd9c135a72f80d5dbff7588dfb0c81458244a89b9e83526e8595880e0a"}, - {file = "libclang-16.0.6.tar.gz", hash = "sha256:4acdde39dfe410c877b4ccc0d4b57eb952100e4ee26bbdf6cfdb88e2033a7d31"}, + {file = "libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5"}, + {file = "libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592"}, + {file = "libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe"}, + {file = "libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f"}, + {file = "libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb"}, + {file = "libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8"}, + {file = "libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250"}, ] +[[package]] +name = "looseversion" +version = "1.3.0" +description = "Version numbering for anarchists and software realists" +optional = false +python-versions = "*" +files = [ + {file = "looseversion-1.3.0-py2.py3-none-any.whl", hash = "sha256:781ef477b45946fc03dd4c84ea87734b21137ecda0e1e122bcb3c8d16d2a56e0"}, + {file = "looseversion-1.3.0.tar.gz", hash = "sha256:ebde65f3f6bb9531a81016c6fef3eb95a61181adc47b7f949e9c0ea47911669e"}, +] + +[[package]] +name = "mako" +version = "1.3.2" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, + {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + [[package]] name = "markdown" version = "3.6" @@ -2204,39 +2937,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.3" +version = "3.8.4" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, - {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, - {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, - {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, - {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, - {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, - {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, - {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, - {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, - {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, - {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, - {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, - {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, - {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, - {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, - {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, - {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, - {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, - {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, - {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, - {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, - {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, - {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, - {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, - {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, - {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, + {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, + {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, + {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, + {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, + {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, + {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, + {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, + {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, + {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, ] [package.dependencies] @@ -2244,7 +2977,7 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" kiwisolver = ">=1.3.1" -numpy = ">=1.21,<2" +numpy = ">=1.21" packaging = ">=20.0" pillow = ">=8" pyparsing = ">=2.3.1" @@ -2797,13 +3530,13 @@ test = ["dm-haiku (>=0.0.3)", "dm-tree (>=0.1.7)", "flax (==0.5.3)"] [[package]] name = "orbax-checkpoint" -version = "0.5.7" +version = "0.5.9" description = "Orbax Checkpoint" optional = false python-versions = ">=3.9" files = [ - {file = "orbax_checkpoint-0.5.7-py3-none-any.whl", hash = "sha256:34aa0b206a4cff9ea29acc96f2a913d0616cb5bcd15272a9806bb0238dd7a38c"}, - {file = "orbax_checkpoint-0.5.7.tar.gz", hash = "sha256:de14549b899220a4f445453967c1ac2d7165b815253342587746005f03a9813b"}, + {file = "orbax_checkpoint-0.5.9-py3-none-any.whl", hash = "sha256:75ccc929122a0511c3e1b5233233f26f2c7fbd1d0734459cf6cf9972447cf2cf"}, + {file = "orbax_checkpoint-0.5.9.tar.gz", hash = "sha256:1fde8891433723157bf6e75d341094d1dabed1dbcfc7cfcfb381de088b468b60"}, ] [package.dependencies] @@ -2893,6 +3626,78 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pandas" +version = "2.2.1" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8df8612be9cd1c7797c93e1c5df861b2ddda0b48b08f2c3eaa0702cf88fb5f88"}, + {file = "pandas-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0f573ab277252ed9aaf38240f3b54cfc90fff8e5cab70411ee1d03f5d51f3944"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f02a3a6c83df4026e55b63c1f06476c9aa3ed6af3d89b4f04ea656ccdaaaa359"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c38ce92cb22a4bea4e3929429aa1067a454dcc9c335799af93ba9be21b6beb51"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c2ce852e1cf2509a69e98358e8458775f89599566ac3775e70419b98615f4b06"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53680dc9b2519cbf609c62db3ed7c0b499077c7fefda564e330286e619ff0dd9"}, + {file = "pandas-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:94e714a1cca63e4f5939cdce5f29ba8d415d85166be3441165edd427dc9f6bc0"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f821213d48f4ab353d20ebc24e4faf94ba40d76680642fb7ce2ea31a3ad94f9b"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c70e00c2d894cb230e5c15e4b1e1e6b2b478e09cf27cc593a11ef955b9ecc81a"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97fbb5387c69209f134893abc788a6486dbf2f9e511070ca05eed4b930b1b02"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101d0eb9c5361aa0146f500773395a03839a5e6ecde4d4b6ced88b7e5a1a6403"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7d2ed41c319c9fb4fd454fe25372028dfa417aacb9790f68171b2e3f06eae8cd"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5d3c00557d657c8773ef9ee702c61dd13b9d7426794c9dfeb1dc4a0bf0ebc7"}, + {file = "pandas-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:06cf591dbaefb6da9de8472535b185cba556d0ce2e6ed28e21d919704fef1a9e"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:88ecb5c01bb9ca927ebc4098136038519aa5d66b44671861ffab754cae75102c"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04f6ec3baec203c13e3f8b139fb0f9f86cd8c0b94603ae3ae8ce9a422e9f5bee"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a935a90a76c44fe170d01e90a3594beef9e9a6220021acfb26053d01426f7dc2"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c391f594aae2fd9f679d419e9a4d5ba4bce5bb13f6a989195656e7dc4b95c8f0"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9d1265545f579edf3f8f0cb6f89f234f5e44ba725a34d86535b1a1d38decbccc"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11940e9e3056576ac3244baef2fedade891977bcc1cb7e5cc8f8cc7d603edc89"}, + {file = "pandas-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acf681325ee1c7f950d058b05a820441075b0dd9a2adf5c4835b9bc056bf4fb"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9bd8a40f47080825af4317d0340c656744f2bfdb6819f818e6ba3cd24c0e1397"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df0c37ebd19e11d089ceba66eba59a168242fc6b7155cba4ffffa6eccdfb8f16"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739cc70eaf17d57608639e74d63387b0d8594ce02f69e7a0b046f117974b3019"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d3558d263073ed95e46f4650becff0c5e1ffe0fc3a015de3c79283dfbdb3df"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4aa1d8707812a658debf03824016bf5ea0d516afdea29b7dc14cf687bc4d4ec6"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:76f27a809cda87e07f192f001d11adc2b930e93a2b0c4a236fde5429527423be"}, + {file = "pandas-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:1ba21b1d5c0e43416218db63037dbe1a01fc101dc6e6024bcad08123e48004ab"}, + {file = "pandas-2.2.1.tar.gz", hash = "sha256:0ab90f87093c13f3e8fa45b48ba9f39181046e8f3317d3aadb2fffbb1b978572"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + [[package]] name = "pathspec" version = "0.12.1" @@ -2992,18 +3797,18 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" @@ -3513,6 +4318,40 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -3538,7 +4377,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3658,6 +4496,125 @@ files = [ [package.dependencies] pyasn1 = ">=0.1.3" +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = true +python-versions = ">=3.7" +files = [ + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = true +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + +[[package]] +name = "scikit-learn" +version = "1.4.1.post1" +description = "A set of python modules for machine learning and data mining" +optional = false +python-versions = ">=3.9" +files = [ + {file = "scikit-learn-1.4.1.post1.tar.gz", hash = "sha256:93d3d496ff1965470f9977d05e5ec3376fb1e63b10e4fda5e39d23c2d8969a30"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c540aaf44729ab5cd4bd5e394f2b375e65ceaea9cdd8c195788e70433d91bbc5"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4310bff71aa98b45b46cd26fa641309deb73a5d1c0461d181587ad4f30ea3c36"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f43dd527dabff5521af2786a2f8de5ba381e182ec7292663508901cf6ceaf6e"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c02e27d65b0c7dc32f2c5eb601aaf5530b7a02bfbe92438188624524878336f2"}, + {file = "scikit_learn-1.4.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:629e09f772ad42f657ca60a1a52342eef786218dd20cf1369a3b8d085e55ef8f"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6145dfd9605b0b50ae72cdf72b61a2acd87501369a763b0d73d004710ebb76b5"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1afed6951bc9d2053c6ee9a518a466cbc9b07c6a3f9d43bfe734192b6125d508"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce03506ccf5f96b7e9030fea7eb148999b254c44c10182ac55857bc9b5d4815f"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ba516fcdc73d60e7f48cbb0bccb9acbdb21807de3651531208aac73c758e3ab"}, + {file = "scikit_learn-1.4.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:78cd27b4669513b50db4f683ef41ea35b5dddc797bd2bbd990d49897fd1c8a46"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a1e289f33f613cefe6707dead50db31930530dc386b6ccff176c786335a7b01c"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0df87de9ce1c0140f2818beef310fb2e2afdc1e66fc9ad587965577f17733649"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712c1c69c45b58ef21635360b3d0a680ff7d83ac95b6f9b82cf9294070cda710"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1754b0c2409d6ed5a3380512d0adcf182a01363c669033a2b55cca429ed86a81"}, + {file = "scikit_learn-1.4.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:1d491ef66e37f4e812db7e6c8286520c2c3fc61b34bf5e59b67b4ce528de93af"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aa0029b78ef59af22cfbd833e8ace8526e4df90212db7ceccbea582ebb5d6794"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:14e4c88436ac96bf69eb6d746ac76a574c314a23c6961b7d344b38877f20fee1"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cd3a77c32879311f2aa93466d3c288c955ef71d191503cf0677c3340ae8ae0"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a3ee19211ded1a52ee37b0a7b373a8bfc66f95353af058a210b692bd4cda0dd"}, + {file = "scikit_learn-1.4.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:234b6bda70fdcae9e4abbbe028582ce99c280458665a155eed0b820599377d25"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.19.5,<2.0" +scipy = ">=1.6.0" +threadpoolctl = ">=2.0.0" + +[package.extras] +benchmark = ["matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "pandas (>=1.1.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.19.12)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.17.2)"] + [[package]] name = "scipy" version = "1.13.0" @@ -3696,9 +4653,47 @@ files = [ numpy = ">=1.22.4,<2.3" [package.extras] -dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "scmrepo" +version = "3.3.1" +description = "scmrepo" +optional = true +python-versions = ">=3.9" +files = [ + {file = "scmrepo-3.3.1-py3-none-any.whl", hash = "sha256:da363c6eadb99f059fcdfb3e651ea62443b614b54cce193a17c0f369e22270fd"}, + {file = "scmrepo-3.3.1.tar.gz", hash = "sha256:e347bf57f799887e3b788b90bfa275e901aafa7c5afbbb2eaaa1419bdfc5d63a"}, +] + +[package.dependencies] +aiohttp-retry = ">=2.5.0" +asyncssh = ">=2.13.1,<3" +dulwich = ">=0.21.6" +fsspec = {version = ">=2024.2.0", extras = ["tqdm"]} +funcy = ">=1.14" +gitpython = ">3" +pathspec = ">=0.9.0" +pygit2 = ">=1.14.0" +pygtrie = ">=2.3.2" +tqdm = "*" + +[package.extras] +dev = ["mypy (==1.9.0)", "scmrepo[tests]", "types-certifi", "types-mock", "types-paramiko", "types-tqdm"] +tests = ["aioresponses (>=0.7,<0.8)", "paramiko (>=3.4.0,<4)", "pytest (>=7,<9)", "pytest-asyncio (>=0.23.2,<1)", "pytest-cov (>=4.1.0)", "pytest-docker (>=1,<4)", "pytest-mock", "pytest-sugar", "pytest-test-utils (>=0.1.0,<0.2)"] + +[[package]] +name = "semver" +version = "3.0.2" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = true +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"}, + {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, +] [[package]] name = "setuptools" @@ -3763,6 +4758,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + [[package]] name = "snowballstemmer" version = "2.2.0" @@ -4000,26 +5006,6 @@ lint = ["docutils-stubs", "flake8", "mypy"] standalone = ["Sphinx (>=5)"] test = ["pytest"] -[[package]] -name = "sqltrie" -version = "0.11.0" -description = "SQL-based prefix tree inspired by pygtrie and python-diskcache" -optional = true -python-versions = ">=3.8" -files = [ - {file = "sqltrie-0.11.0-py3-none-any.whl", hash = "sha256:132c3d2675dd14970093e2f8dcde906f7a3c900c4477641da71c0c8627eb5a0e"}, - {file = "sqltrie-0.11.0.tar.gz", hash = "sha256:e613a74843e2b55ce1d20d333100d6a41127a1d6c12f835915f58fbd13944a82"}, -] - -[package.dependencies] -attrs = "*" -orjson = {version = "*", markers = "implementation_name == \"cpython\""} -pygtrie = "*" - -[package.extras] -dev = ["sqltrie[tests]"] -tests = ["mypy (==0.971)", "pyinstaller", "pytest (==7.2.0)", "pytest-benchmark", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.5)"] - [[package]] name = "sqlalchemy" version = "2.0.29" @@ -4123,6 +5109,40 @@ dev = ["build", "flake8"] doc = ["sphinx"] test = ["pytest", "pytest-cov"] +[[package]] +name = "sqltrie" +version = "0.11.0" +description = "SQL-based prefix tree inspired by pygtrie and python-diskcache" +optional = true +python-versions = ">=3.8" +files = [ + {file = "sqltrie-0.11.0-py3-none-any.whl", hash = "sha256:132c3d2675dd14970093e2f8dcde906f7a3c900c4477641da71c0c8627eb5a0e"}, + {file = "sqltrie-0.11.0.tar.gz", hash = "sha256:e613a74843e2b55ce1d20d333100d6a41127a1d6c12f835915f58fbd13944a82"}, +] + +[package.dependencies] +attrs = "*" +orjson = {version = "*", markers = "implementation_name == \"cpython\""} +pygtrie = "*" + +[package.extras] +dev = ["sqltrie[tests]"] +tests = ["mypy (==0.971)", "pyinstaller", "pytest (==7.2.0)", "pytest-benchmark", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.5)"] + +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = true +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + [[package]] name = "tensorboard" version = "2.15.2" @@ -4616,13 +5636,13 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.10.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -4636,17 +5656,6 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] -[[package]] -name = "tzdata" -version = "2024.1" -description = "Provider of IANA time zone data" -optional = true -python-versions = ">=2" -files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, -] - [[package]] name = "urllib3" version = "2.2.1" @@ -4695,6 +5704,43 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "voluptuous" +version = "0.14.2" +description = "Python data validation library" +optional = true +python-versions = ">=3.8" +files = [ + {file = "voluptuous-0.14.2-py3-none-any.whl", hash = "sha256:efc1dadc9ae32a30cc622602c1400a17b7bf8ee2770d64f70418144860739c3b"}, + {file = "voluptuous-0.14.2.tar.gz", hash = "sha256:533e36175967a310f1b73170d091232bf881403e4ebe52a9b4ade8404d151f5d"}, +] + +[[package]] +name = "waitress" +version = "3.0.0" +description = "Waitress WSGI server" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"}, + {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, +] + +[package.extras] +docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] +testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = true +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [[package]] name = "werkzeug" version = "3.0.2" @@ -4752,16 +5798,6 @@ files = [ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecee4132c6cd2ce5308e21672015ddfed1ff975ad0ac8d27168ea82e71413f55"}, - {file = "wrapt-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2020f391008ef874c6d9e208b24f28e31bcb85ccff4f335f15a3251d222b92d9"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2feecf86e1f7a86517cab34ae6c2f081fd2d0dac860cb0c0ded96d799d20b335"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:240b1686f38ae665d1b15475966fe0472f78e71b1b4903c143a842659c8e4cb9"}, - {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9008dad07d71f68487c91e96579c8567c98ca4c3881b9b113bc7b33e9fd78b8"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6447e9f3ba72f8e2b985a1da758767698efa72723d5b59accefd716e9e8272bf"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acae32e13a4153809db37405f5eba5bac5fbe2e2ba61ab227926a22901051c0a"}, - {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49ef582b7a1152ae2766557f0550a9fcbf7bbd76f43fbdc94dd3bf07cc7168be"}, - {file = "wrapt-1.14.1-cp311-cp311-win32.whl", hash = "sha256:358fe87cc899c6bb0ddc185bf3dbfa4ba646f05b1b0b9b5a27c2cb92c2cea204"}, - {file = "wrapt-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:26046cd03936ae745a502abf44dac702a5e6880b2b01c29aea8ddf3353b68224"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, @@ -4941,8 +5977,26 @@ files = [ ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "znflow" +version = "0.1.14" +description = "A general purpose framework for building and running computational graphs." +optional = true +python-versions = ">=3.8,<4.0" +files = [ + {file = "znflow-0.1.14-py3-none-any.whl", hash = "sha256:f94f21cdaece949754e6dd5beaedfb078b9331ca49e32d9a2dfaa4ac1d8f8324"}, + {file = "znflow-0.1.14.tar.gz", hash = "sha256:bf85dbb4c816a3c1ae98ed62f75feb10a22032e8bccf8d016ee6d406873c9c03"}, +] + +[package.dependencies] +matplotlib = ">=3.6.3,<4.0.0" +networkx = ">=3.0,<4.0" + +[package.extras] +dask = ["bokeh (>=2.4.2,<3.0.0)", "dask (>=2022.12.1,<2023.0.0)", "dask-jobqueue (>=0.8.1,<0.9.0)", "distributed (>=2022.12.1,<2023.0.0)"] [[package]] name = "znh5md" @@ -5019,4 +6073,4 @@ zntrack = ["zntrack"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "02e6652599fb8121cb7d5fb59e151a32413f31c6a64e05904f147397d62687bf" +content-hash = "197f73688e0d11a4b3a4e6bdbecb096b905c13e4e4959333f8ffe1799d0e2826" diff --git a/pyproject.toml b/pyproject.toml index ca243ece..7c202e05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,8 @@ matscipy = "^0.8.0" znh5md = "^0.1.7" pydantic = "^2.3.0" jax = "^0.4.25" -jax-md = {git = "https://github.com/jax-md/jax-md.git"} zntrack = {version = "^0.7.2", optional = true} +mlflow = {version = "^2.11.3", extras = ["mlflow"]} [tool.poetry.extras] zntrack = ["zntrack"] @@ -53,10 +53,6 @@ sphinx-copybutton = "^0.5.2" sphinx-autodoc-typehints = "^1.25.2" furo = "^2023.9.10" - -[tool.poetry.group.extras.dependencies] -mlflow = "^2.11.3" - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From c9a9278bfe64cc20cf5dc8e547526ceaa2df4de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 16:48:15 +0200 Subject: [PATCH 162/192] removed merge comment --- apax/train/callbacks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 8d8a18f9..5cc47419 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -51,7 +51,6 @@ class CustomDialect(csv.excel): self.csv_file.flush() -<<<<<<< HEAD class CSVLoggerApax(CSVLogger): def __init__(self, filename, separator=",", append=False): super().__init__(filename, separator=",", append=False) From eef1c11816c8c207ce11ffa506f82642d4c36694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 16:48:47 +0200 Subject: [PATCH 163/192] added test dataset to benzene util function --- apax/utils/datasets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apax/utils/datasets.py b/apax/utils/datasets.py index 6e708c4d..d6625b6d 100644 --- a/apax/utils/datasets.py +++ b/apax/utils/datasets.py @@ -64,9 +64,10 @@ def download_md22_benzene_CCSDT(data_path): zip_ref.extractall(data_path) train_file_path = data_path / "benzene_ccsd_t-train.xyz" + test_file_path = data_path / "benzene_ccsd_t-test.xyz" os.remove(file_path) - return train_file_path + return train_file_path, test_file_path def modify_xyz_file(file_path, target_string, replacement_string): From 9f7bbe644d0c0a324441e560a9785539d1a4eb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 16:49:42 +0200 Subject: [PATCH 164/192] Added transfer learning code example --- examples/03_Transfer_Learning.ipynb | 312 +++++++++++++++++++++++++++- 1 file changed, 305 insertions(+), 7 deletions(-) diff --git a/examples/03_Transfer_Learning.ipynb b/examples/03_Transfer_Learning.ipynb index a87e15ea..0172f8d1 100644 --- a/examples/03_Transfer_Learning.ipynb +++ b/examples/03_Transfer_Learning.ipynb @@ -14,7 +14,7 @@ "\n", "Alternatively, the level of theory might not change, but the dataset is extended.\n", "This is the case in learning on the fly scenarios.\n", - "For a demonstration of using transfer learning for learning on the fly, see the corresponding example from the IPSuite documentation LINK.\n", + "For a demonstration of using transfer learning for learning on the fly, see the corresponding example from the [IPSuite documentation](https://ipsuite.readthedocs.io/en/latest/).\n", "\n", "\n", "apax comes with discriminative transfer learning capabilities out of the box.\n", @@ -48,19 +48,309 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", - "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets\n", + "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets, download_benzene_DFT\n", "import os\n", + "from apax.utils.helpers import mod_config\n", + "import yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Acquire Datasets\n", + "\n", + "For this demonstration we will use the DFT and CC versions of the benzene MD17 dataset.\n", + "We start by downloading both and saving them in an appropriate format." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Download DFT Data\n", "\n", "data_path = Path(\"project\")\n", - "file_path = download_md22_benzene_CCSDT(data_path)\n", - "os.remove(data_path / \"benzene_ccsd_t-test.xyz\")\n", + "dft_file_path = download_benzene_DFT(data_path)\n", + "dft_file_path = mod_md_datasets(dft_file_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Download CCSD(T) Data\n", + "\n", + "data_path = Path(\"project\")\n", + "cc_file_path, _ = download_md22_benzene_CCSDT(data_path)\n", + "cc_file_path = mod_md_datasets(cc_file_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pretrain Model\n", + "\n", + "First, we will train a model on the \"large\" (in relative terms) but less accurate DFT dataset.\n", + "A standard model with default optimizers will do just fine." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ms/miniconda3/envs/apax311/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + } + ], + "source": [ + "!apax template train" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"n_train\": 1000,\n", + " \"n_valid\": 200,\n", + " \"batch_size\": 8,\n", + " \"valid_batch_size\": 100,\n", + " \"experiment\": \"benzene_dft\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(dft_file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " },\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 16:25:57 | Running on [cuda(id=0)]\n", + "INFO | 16:25:57 | Initializing Callbacks\n", + "INFO | 16:25:57 | Initializing Loss Function\n", + "INFO | 16:25:57 | Initializing Metrics\n", + "INFO | 16:25:57 | Running Input Pipeline\n", + "INFO | 16:25:57 | Read data file project/benzene_mod.xyz\n", + "INFO | 16:25:57 | Loading data from project/benzene_mod.xyz\n", + "INFO | 16:26:06 | Computing per element energy regression.\n", + "INFO | 16:26:06 | Initializing Model\n", + "INFO | 16:26:06 | initializing 1 models\n", + "INFO | 16:26:10 | Initializing Optimizer\n", + "INFO | 16:26:10 | Beginning Training\n", + "Epochs: 0%| | 0/100 [00:00 CC Fine Tuning\n", + "\n", + "Finally, we can fine tine a model that was pretrained on DFT data.\n", + "The model architecture remains unchanged for all 3 runs.\n", + "However, for fine-tuning we need to specify the path to the base model and how to deal with its parameters.\n", + "For each parameter group we can choose to freeze, to reset it or to keep training it.\n", + "It is certainly advisable to experiment with different strategies, but a good start consists in freezing the embedding layer if the system we transfer to remains the same and resetting the scale-shift layer if the level of theory changes (DFT and CC have different energy scales).\n", + "\n", + "Make sure to carefully inspect the config options below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 100,\n", + " \"data\": {\n", + " \"n_train\": 50,\n", + " \"n_valid\": 10,\n", + " \"batch_size\": 4,\n", + " \"valid_batch_size\": 10,\n", + " \"experiment\": \"benzene_cc_ft\",\n", + " \"directory\": \"project/models\",\n", + " \"data_path\": str(cc_file_path),\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " },\n", + " \"optimizer\": {\n", + " \"emb_lr\": 0.00, # freeze embedding layer\n", + " \"nn_lr\": 0.0005, # lower lr\n", + " \"scale_lr\": 0.001, # lower lr\n", + " \"shift_lr\": 0.005, # lower lr\n", + " },\n", + " \"checkpoints\": {\n", + " \"base_model_checkpoint\": \"project/models/benzene_dft\", # pretrained model\n", + " \"reset_layers\": [\"scale_shift\"], # reset scale-shift layer\n", + " }\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"config_cc_ft.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 16:27:20 | Running on [cuda(id=0)]\n", + "INFO | 16:27:20 | Initializing Callbacks\n", + "INFO | 16:27:20 | Initializing Loss Function\n", + "INFO | 16:27:20 | Initializing Metrics\n", + "INFO | 16:27:20 | Running Input Pipeline\n", + "INFO | 16:27:20 | Read data file project/benzene_ccsd_t-train_mod.xyz\n", + "INFO | 16:27:20 | Loading data from project/benzene_ccsd_t-train_mod.xyz\n", + "INFO | 16:27:20 | Computing per element energy regression.\n", + "INFO | 16:27:20 | Initializing Model\n", + "INFO | 16:27:20 | initializing 1 models\n", + "INFO | 16:27:24 | Initializing Optimizer\n", + "INFO | 16:27:24 | loading checkpoint from project/models/benzene_dft/best\n", + "INFO | 16:27:24 | Transferring parameters from project/models/benzene_dft\n", + "INFO | 16:27:24 | Transferring parameter: radial_fn\n", + "INFO | 16:27:24 | Transferring parameter: dense_0\n", + "INFO | 16:27:24 | Transferring parameter: dense_0\n", + "INFO | 16:27:24 | Transferring parameter: dense_1\n", + "INFO | 16:27:24 | Transferring parameter: dense_1\n", + "INFO | 16:27:24 | Transferring parameter: dense_2\n", + "INFO | 16:27:24 | Transferring parameter: dense_2\n", + "INFO | 16:27:24 | Beginning Training\n", + "Epochs: 0%| | 0/100 [00:00 Date: Fri, 5 Apr 2024 17:07:40 +0200 Subject: [PATCH 165/192] linting --- apax/bal/feature_maps.py | 1 - apax/data/input_pipeline.py | 1 - apax/train/callbacks.py | 38 ----------------------------- apax/train/trainer.py | 10 +++++--- examples/03_Transfer_Learning.ipynb | 1 - 5 files changed, 6 insertions(+), 45 deletions(-) diff --git a/apax/bal/feature_maps.py b/apax/bal/feature_maps.py index 66223af8..565439ed 100644 --- a/apax/bal/feature_maps.py +++ b/apax/bal/feature_maps.py @@ -12,7 +12,6 @@ class FeatureTransformation(BaseModel): - def apply(self, model: EnergyModel) -> FeatureMap: return model diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index 267f7d1b..dfa9e75e 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -50,7 +50,6 @@ def __init__( ignore_labels=False, cache_path=".", ) -> None: - self.n_epochs = n_epochs self.cutoff = cutoff self.n_jit_steps = n_jit_steps diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index 5cc47419..fee8459c 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -13,44 +13,6 @@ log = logging.getLogger(__name__) -class CSVLoggerApax(CSVLogger): - def __init__(self, filename, separator=",", append=False): - super().__init__(filename, separator=",", append=False) - - def on_test_batch_end(self, batch, logs=None): - logs = logs or {} - - def handle_value(k): - is_zero_dim_ndarray = isinstance(k, np.ndarray) and k.ndim == 0 - if isinstance(k, str): - return k - elif isinstance(k, collections.abc.Iterable) and not is_zero_dim_ndarray: - return f"\"[{', '.join(map(str, k))}]\"" - else: - return k - - if self.keys is None: - self.keys = sorted(logs.keys()) - - if not self.writer: - - class CustomDialect(csv.excel): - delimiter = self.sep - - fieldnames = ["batch"] + self.keys - - self.writer = csv.DictWriter( - self.csv_file, fieldnames=fieldnames, dialect=CustomDialect - ) - if self.append_header: - self.writer.writeheader() - - row_dict = collections.OrderedDict({"batch": batch}) - row_dict.update((key, handle_value(logs.get(key, "NA"))) for key in self.keys) - self.writer.writerow(row_dict) - self.csv_file.flush() - - class CSVLoggerApax(CSVLogger): def __init__(self, filename, separator=",", append=False): super().__init__(filename, separator=",", append=False) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index aae54123..9f77864c 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -130,10 +130,12 @@ def fit( epoch_loss["val_loss"] /= val_steps_per_epoch epoch_loss["val_loss"] = float(epoch_loss["val_loss"]) - epoch_metrics.update({ - f"val_{key}": float(val) - for key, val in val_batch_metrics.compute().items() - }) + epoch_metrics.update( + { + f"val_{key}": float(val) + for key, val in val_batch_metrics.compute().items() + } + ) epoch_metrics.update({**epoch_loss}) diff --git a/examples/03_Transfer_Learning.ipynb b/examples/03_Transfer_Learning.ipynb index 0172f8d1..9ecdf64a 100644 --- a/examples/03_Transfer_Learning.ipynb +++ b/examples/03_Transfer_Learning.ipynb @@ -54,7 +54,6 @@ "source": [ "from pathlib import Path\n", "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets, download_benzene_DFT\n", - "import os\n", "from apax.utils.helpers import mod_config\n", "import yaml" ] From cb2f9d0c8acdbd3a1878252f29f2fcb0340ff600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 18:57:14 +0200 Subject: [PATCH 166/192] added batch active learning example notebook. --- examples/04_Batch_Data_Selection.ipynb | 428 ++++++++++++++++++++++++- 1 file changed, 421 insertions(+), 7 deletions(-) diff --git a/examples/04_Batch_Data_Selection.ipynb b/examples/04_Batch_Data_Selection.ipynb index 9ca270be..fa4f7435 100644 --- a/examples/04_Batch_Data_Selection.ipynb +++ b/examples/04_Batch_Data_Selection.ipynb @@ -16,26 +16,440 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "# TODO Model Training\n", - "# TODO run MD\n", - "# TODO illustrate selection vs max uncertainty" + "from pathlib import Path\n", + "import yaml\n", + "\n", + "from ase.md.velocitydistribution import MaxwellBoltzmannDistribution\n", + "from ase import units\n", + "from ase.md.langevin import Langevin\n", + "from ase.optimize.fire import FIRE\n", + "from ase.io.trajectory import TrajectoryWriter\n", + "from ase.io import read\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "from apax.bal import api\n", + "from apax.md import ASECalculator\n", + "from apax.utils.datasets import download_md22_benzene_CCSDT, mod_md_datasets\n", + "from apax.utils.helpers import mod_config" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dataset Acquisition" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Download CCSD(T) Data\n", + "data_path = Path(\"project\")\n", + "cc_train_file_path, cc_val_file_path = download_md22_benzene_CCSDT(data_path)\n", + "cc_train_file_path = mod_md_datasets(cc_train_file_path)\n", + "cc_val_file_path = mod_md_datasets(cc_val_file_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Training\n", + "\n", + "Unlike simpler data selection methods, such as random selection, we first need to train a model.\n", + "It is the representation learned by the model which will serve as the basis for our similarity metric." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ms/miniconda3/envs/apax311/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + } + ], + "source": [ + "!apax template train" + ] + }, + { + "cell_type": "code", + "execution_count": 10, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "config_path = Path(\"config.yaml\")\n", + "\n", + "config_updates = {\n", + " \"n_epochs\": 200,\n", + " \"data\": {\n", + " \"batch_size\": 4,\n", + " \"valid_batch_size\": 100,\n", + " \"experiment\": \"benzene\",\n", + " \"directory\": \"project/models\",\n", + " \"train_data_path\": str(cc_train_file_path),\n", + " \"val_data_path\": str(cc_val_file_path),\n", + " \"data_path\": None,\n", + " \"energy_unit\": \"kcal/mol\",\n", + " \"pos_unit\": \"Ang\",\n", + " },\n", + "}\n", + "config_dict = mod_config(config_path, config_updates)\n", + "\n", + "with open(\"config.yaml\", \"w\") as conf:\n", + " yaml.dump(config_dict, conf, default_flow_style=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ms/miniconda3/envs/apax311/lib/python3.11/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n", + " pid, fd = os.forkpty()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 18:13:29 | Running on [cuda(id=0)]\n", + "INFO | 18:13:29 | Initializing Callbacks\n", + "INFO | 18:13:29 | Initializing Loss Function\n", + "INFO | 18:13:29 | Initializing Metrics\n", + "INFO | 18:13:29 | Running Input Pipeline\n", + "INFO | 18:13:29 | Read training data file project/benzene_ccsd_t-train_mod.xyz\n", + "INFO | 18:13:29 | Read validation data file project/benzene_ccsd_t-test_mod.xyz\n", + "INFO | 18:13:29 | Loading data from project/benzene_ccsd_t-train_mod.xyz\n", + "INFO | 18:13:29 | Loading data from project/benzene_ccsd_t-test_mod.xyz\n", + "INFO | 18:13:30 | Computing per element energy regression.\n", + "INFO | 18:13:30 | Initializing Model\n", + "INFO | 18:13:30 | initializing 1 models\n", + "INFO | 18:13:34 | Initializing Optimizer\n", + "INFO | 18:13:34 | Beginning Training\n", + "Epochs: 0%| | 0/200 [00:00" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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T4Ver4der8fq1avx7LPPQq/Xo6ioqMeeu6Bfv34YOXKkatuIESNw8OBBAJDPsyf+Pdxzzz1YuHAhrrzySowePRqzZ8/GnXfeiUWLFgHo2ecejHDOt7i4OKBoxOl0or6+vse8JkIEHThwACtWrFBNX+/J5//ll1+irq4OAwYMkD8PDxw4gLvuuguDBg0CkLzzpxDqYoxGI8aOHYvPPvtM3uZ2u/HZZ59hwoQJSVxZYpAkCQsWLMD777+PlStXYvDgwar7x44dC4PBoHo9KioqcPDgwW7/ekydOhXff/89tm7dKt/GjRuHWbNmyf/vqecuOPPMMwPaJezatQsDBw4EAAwePBjFxcWq16CpqQnr1q3r9q+B1WqFVqv+iNXpdHC73QB69rkHI5zznTBhAhobG7Fp0yZ5n5UrV8LtdmP8+PFdvuZ4I0TQ7t278emnn6JPnz6q+3vy+c+ePRvfffed6vOwpKQE99xzDz755BMASTz/hKVhk5C8/fbbkslkkl5//XXphx9+kObPny/l5uZKtbW1yV5a3PnFL34hmc1madWqVdLhw4flm9Vqlfe5+eabpQEDBkgrV66UNm7cKE2YMEGaMGFCEledOJRVY5LU8899/fr1kl6vlx577DFp9+7d0pIlS6SMjAzprbfekvd54oknpNzcXOnf//639N1330kXXXSRNHjwYKmtrS2JK4+d6667Turfv7+0bNkyad++fdJ7770n9e3bV/r1r38t79PTzr25uVnasmWLtGXLFgmA9Pvf/17asmWLXBUVzvnOmDFDGjNmjLRu3Trpq6++koYNGyZdddVVyTqliOjo/O12u3ThhRdKpaWl0tatW1WfhzabTT5GTz3/YPhXjUlScs6fQihJPPfcc9KAAQMko9EonX766dI333yT7CUlBABBb6+99pq8T1tbm/TLX/5SysvLkzIyMqSf/exn0uHDh5O36ATiL4R6w7l/9NFH0qhRoySTySQNHz5ceumll1T3u91u6cEHH5SKiookk8kkTZ06VaqoqEjSauNHU1OTdPvtt0sDBgyQ0tLSpPLycumBBx5QXfR62rl//vnnQf/er7vuOkmSwjvf48ePS1dddZWUlZUl5eTkSNdff73U3NychLOJnI7Of9++fSE/Dz///HP5GD31/IMRTAgl4/w5fZ4QQgghvRbmCBFCCCGk10IhRAghhJBeC4UQIYQQQnotFEKEEEII6bVQCBFCCCGk10IhRAghhJBeC4UQIYQQQnotFEKEEEII6bVQCBFCCCGk10IhRAjpVsyZMwcXX3xxspdBCOkhUAgRQgghpNdCIUQI6bZMmTIFt956K+644w7k5eWhqKgIf/vb39Da2orrr78e2dnZGDp0KD7++GP5MS6XC3PnzsXgwYORnp6OE088EX/6059Ux3U6nbjtttuQm5uLPn364N5778V1112ncqLcbjcWLVokH+eUU07Bu+++21WnTgiJExRChJBuzRtvvIG+ffti/fr1uPXWW/GLX/wCl19+OSZOnIjNmzdj+vTpmD17NqxWKwCPgCktLcU///lP/PDDD3jooYdw//334x//+Id8zCeffBJLlizBa6+9hjVr1qCpqQkffPCB6nkXLVqExYsX44UXXsD27dtx55134pprrsHq1au78vQJITHC6fOEkG7FnDlz0NjYiA8++ABTpkyBy+XCl19+CcDj9pjNZlxyySVYvHgxAKC2thb9+vXD2rVrccYZZwQ95oIFC1BbWys7OsXFxbj77rtx9913y8ctLy/HmDFj8MEHH8BmsyE/Px+ffvopJkyYIB/nxhtvhNVqxdKlSxP5EhBC4og+2QsghJBYOPnkk+X/63Q69OnTB6NHj5a3FRUVAQDq6urkbc8//zxeffVVHDx4EG1tbbDb7fjRj34EALBYLDhy5AhOP/101XHHjh0Lt9sNANizZw+sVivOPfdc1VrsdjvGjBkT93MkhCQOCiFCSLfGYDCoftZoNKptGo0GAGQR8/bbb+Puu+/GM888gwkTJiA7Oxu/+93vsG7durCfs6WlBQDwn//8B/3791fdZzKZojoPQkhyoBAihPQq1qxZg4kTJ+KXv/ylvG3v3r3y/81mM4qKirBhwwacffbZADyhsc2bN8uu0ciRI2EymXDw4EFMnjy5S9dPCIkvFEKEkF7FsGHDsHjxYnzyyScYPHgw3nzzTWzYsAGDBw+W97n11luxaNEiDB06FMOHD8dzzz2HhoYG2V3Kzs7G3XffjTvvvBNutxuTJk2CxWLBmjVrkJOTg+uuuy5Zp0cIiRAKIUJIr+Kmm27Cli1b8POf/xwajQZXXXUVfvnLX6pK7O+9917U1tbi2muvhU6nw/z583HeeedBp9PJ+zz66KMoKCjAokWLUFlZidzcXJx66qm4//77k3FahJAoYdUYIYR0gtvtxogRI3DFFVfg0UcfTfZyCCFxhI4QIYT4ceDAAfzvf//D5MmTYbPZ8Oc//xn79u3D1VdfneylEULiDBsqEkKIH1qtFq+//jpOO+00nHnmmfj+++/x6aefYsSIEcleGiEkzjA0RgghhJBeCx0hQgghhPRaKIQIIYQQ0muhECKEEEJIr4VCiBBCCCG9FgohQgghhPRaKIQIIYQQ0muhECKEEEJIr4VCiBBCCCG9FgohQgghhPRa/j/MvcWI2WrmlgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "ax.plot(energies)\n", + "ax.scatter(selected_indices, selection_energies, marker=\"x\", color=\"red\", label=\"selection\")\n", + "ax.set_ylabel(\"Energy / eV\")\n", + "ax.set_xlabel(\"Image\")\n", + "ax.legend()" + ] } ], "metadata": { + "kernelspec": { + "display_name": "apax311", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" } }, "nbformat": 4, From 0be92aac3ee1ed741a55330fa1bad32a85727b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Fri, 5 Apr 2024 18:57:34 +0200 Subject: [PATCH 167/192] fixed bug in otfinmemorydataset when nepochs is 1 --- apax/data/input_pipeline.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index dfa9e75e..9b09484d 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -251,18 +251,19 @@ def cleanup(self): class OTFInMemoryDataset(InMemoryDataset): def __iter__(self): - epoch = 0 - while epoch < self.n_epochs or len(self.buffer) > 0: + outer_count = 0 + max_iter = self.n_data * self.n_epochs + while outer_count < max_iter: yield self.buffer.popleft() space = self.buffer_size - len(self.buffer) if self.count + space > self.n_data: space = self.n_data - self.count - if self.count >= self.n_data and epoch < self.n_epochs: - epoch += 1 + if self.count >= self.n_data: self.count = 0 self.enqueue(space) + outer_count += 1 def shuffle_and_batch(self): """Shuffles and batches the inputs/labels. This function prepares the From c119992aea3c73b4c4b1147987f6b698d1a8625b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Mon, 8 Apr 2024 10:13:53 +0200 Subject: [PATCH 168/192] remove debug comment --- apax/train/trainer.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 00b5b18d..39e6c8fc 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -95,9 +95,6 @@ def fit( callbacks.on_train_batch_begin(batch=batch_idx) batch = next(batch_train_ds) - - # print(jax.tree_map(lambda x: x.devices(), batch)) - ( (state, train_batch_metrics), batch_loss, From bad2e87c61f12449569bb79a4721dcf57b0327b9 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:13:21 +0200 Subject: [PATCH 169/192] docs --- apax/config/md_config.py | 65 +++++++++---------- apax/config/train_config.py | 122 +++++++++++++++++++++++------------- apax/train/callbacks.py | 1 + apax/train/eval.py | 59 ++++++++++++++++- apax/train/run.py | 56 ++++++++++++++++- apax/train/trainer.py | 44 ++++++++++++- 6 files changed, 266 insertions(+), 81 deletions(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 989b04ea..08a98d2d 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -35,46 +35,47 @@ class NPTOptions(NVTOptions, extra="forbid"): class MDConfig(BaseModel, frozen=True, extra="forbid"): - """Configuration for a NHC molecular dynamics simulation. + """ + Configuration for a NHC molecular dynamics simulation. - Attributes + Parameters ---------- - seed: - Random seed for momentum initialization. - temperature: - Temperature of the simulation in Kelvin. - dt: - Time step in fs. - duration: - Total simulation time in fs. - n_inner: - Number of compiled simulation steps (i.e. number of iterations of the + seed : int, default = 1 + | Random seed for momentum initialization. + temperature : float, default = 298.15 + | Temperature of the simulation in Kelvin. + dt : float, default = 0.5 + | Time step in fs. + duration : float, required + | Total simulation time in fs. + n_inner : int, default = 100 + | Number of compiled simulation steps (i.e. number of iterations of the `jax.lax.fori_loop` loop). Also determines atoms buffer size. - sampling_rate: - Interval between saving frames. - buffer_size: - Number of collected frames to be dumped at once. - dr_threshold: - Skin of the neighborlist. - extra_capacity: - JaxMD allocates a maximal number of neighbors. + sampling_rate : int, default = 10 + | Interval between saving frames. + buffer_size : int, default = 100 + | Number of collected frames to be dumped at once. + dr_threshold : float, default = 0.5 + | Skin of the neighborlist. + extra_capacity : int, default = 0 + | JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. - initial_structure: - Path to the starting structure of the simulation. - sim_dir: - Directory where simulation file will be stored. - traj_name: - Name of the trajectory file. - restart: - Whether the simulation should restart from the latest configuration + initial_structure : str, required + | Path to the starting structure of the simulation. + sim_dir : str, default = "." + | Directory where simulation file will be stored. + traj_name : str, default = "md.h5" + | Name of the trajectory file. + restart : bool, default = True + | Whether the simulation should restart from the latest configuration in `traj_name`. - checkpoint_interval: - Number of time steps between saving + checkpoint_interval : int, default = 50_000 + | Number of time steps between saving full simulation state checkpoints. These will be loaded with the `restart` option. - disable_pbar: - Disables the MD progressbar. + disable_pbar : bool, False + | Disables the MD progressbar. """ seed: int = 1 diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 42f44a37..4643b6ec 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -27,27 +27,32 @@ class DataConfig(BaseModel, extra="forbid"): Parameters ---------- - directory: Path to the directory where the training results and - checkpoints will be written. - experiment: Name of the model. Distinguishes it from the other models - trained in the same `directory`. - data_path: Path to a single dataset file. Set either this or `val_data_path` and - `train_data_path`. - train_data_path: Path to a training dataset. Set this and `val_data_path` - if your data comes pre-split. - val_data_path: Path to a validation dataset. Set this and `train_data_path` - if your data comes pre-split. - test_data_path: Path to a test dataset. Set this, `train_data_path` and - `val_data_path` if your data comes pre-split. - n_train: Number of training datapoints from `data_path`. - n_valid: Number of validation datapoints from `data_path`. - batch_size: Number of training examples to be evaluated at once. - valid_batch_size: Number of validation examples to be evaluated at once. - shuffle_buffer_size: Size of the `tf.data` shuffle buffer. - additional_properties_info: - dict of property name, shape (ragged or fixed) pairs - energy_regularisation: Magnitude of the regularization in the per-element - energy regression. + directory : str, required + | Path to directory where training results and checkpoints are written. + experiment : str, required + | Model name distinguishing from others in directory. + data_path : str, required if train_ and val_data_path is not specified + | Path to single dataset file. + train_data_path : str, required if data_path is not specified + | Path to training dataset. + val_data_path : str, required if data_path is not specified + | Path to validation dataset. + test_data_path : str, optional + | Path to test dataset. + n_train : int, default = 1000 + | Number of training datapoints from `data_path`. + n_valid : int, default = 100 + | Number of validation datapoints from `data_path`. + batch_size : int, default = 32 + | Number of training examples to be evaluated at once. + valid_batch_size : int, default = 100 + | Number of validation examples to be evaluated at once. + shuffle_buffer_size : int, default = 1000 + | Size of the `tf.data` shuffle buffer. + additional_properties_info : dict, optional + | dict of property name, shape (ragged or fixed) pairs + energy_regularisation : + | Magnitude of the regularization in the per-element energy regression. """ directory: str @@ -134,13 +139,18 @@ class ModelConfig(BaseModel, extra="forbid"): Parameters ---------- - n_basis: Number of uncontracted gaussian basis functions. - n_radial: Number of contracted basis functions. - r_min: Position of the first uncontracted basis function's mean. - r_max: Cutoff radius of the descriptor. - nn: Number of hidden layers and units in those layers. - b_init: Initialization scheme for the neural network biases. - Either `normal` or `zeros`. + n_basis : + | Number of uncontracted gaussian basis functions. + n_radial : + | Number of contracted basis functions. + r_min : + | Position of the first uncontracted basis function's mean. + r_max : + | Cutoff radius of the descriptor. + nn : + | Number of hidden layers and units in those layers. + b_init : + | Initialization scheme for the neural network biases. Either `normal` or `zeros`. """ n_basis: PositiveInt = 7 @@ -312,26 +322,48 @@ class CheckpointConfig(BaseModel, extra="forbid"): class Config(BaseModel, frozen=True, extra="forbid"): """ - Main configuration of a apax training run. + Main configuration of a apax training run. Parameter that are cofig classes will + be generated by parsing the config.yaml file and are specified as shown :ref:`here `: + + .. code-block:: yaml + + data: + directory: models/ + experiment: apax + . + . Parameters ---------- - - n_epochs: Number of training epochs. - patience: Number of epochs without improvement before trainings gets terminated. - seed: Random seed. - n_models: Number of models to be trained at once. - n_jitted_steps: Number of train batches to be processed in a compiled loop. + n_epochs : int, required + | Number of training epochs. + patience : int, optional + | Number of epochs without improvement before trainings gets terminated. + seed : int, default = 1 + | Random seed. + n_models : int, default = 1 + | Number of models to be trained at once. + n_jitted_steps : int, default = 1 + | Number of train batches to be processed in a compiled loop. Can yield singificant speedups for small structures or small batch sizes. - data: :class: `Data` configuration. - model: :class: `Model` configuration. - metrics: List of :class: `metric` configurations. - loss: List of :class: `loss` function configurations. - optimizer: :class: `Optimizer` configuration. - callbacks: List of :class: `callback` configurations. - progress_bar: Progressbar configuration. - checkpoints: Checkpoint configuration. - data_parallel: Automatically uses all available GPUs for data parallel training. + data : :class:`.DataConfig` + | Data configuration. + model : :class:`.ModelConfig` + | Model configuration. + metrics : List of :class:`.MetricsConfig` + | Metrics configuration. + loss : List of :class:`.LossConfig` + | Loss configuration. + optimizer : :class:`.OptimizerConfig` + | Loss optimizer configuration. + callbacks : List of various CallBack classes + | Possible callbacks are :class:`.CSVCallback`, :class:`.TBCallback`, :class:`.MLFlowCallback` + progress_bar : :class:`.TrainProgressbarConfig` + | Progressbar configuration. + checkpoints : :class:`.CheckpointConfig` + | Checkpoint configuration. + data_parallel : bool, default = True + | Automatically uses all available GPUs for data parallel training. Set to false to force single device training. """ @@ -340,7 +372,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): seed: int = 1 n_models: int = 1 n_jitted_steps: int = 1 - data_parallel: int = True + data_parallel: bool = True data: DataConfig model: ModelConfig = ModelConfig() diff --git a/apax/train/callbacks.py b/apax/train/callbacks.py index fee8459c..1c99fc8f 100644 --- a/apax/train/callbacks.py +++ b/apax/train/callbacks.py @@ -72,6 +72,7 @@ def initialize_callbacks(config: Config, model_version_path: Path): "model": dummy_model, }, } + names = [conf.name for conf in callback_configs] if "csv" in names and "tensorboard" in names: msg = ( diff --git a/apax/train/eval.py b/apax/train/eval.py index e8b2cb5c..82abf6a4 100644 --- a/apax/train/eval.py +++ b/apax/train/eval.py @@ -34,6 +34,26 @@ def get_test_idxs(atoms_list, used_idxs, n_test=-1): def load_test_data( config, model_version_path, eval_path, n_test=-1 ): # TODO double code run.py in progress + """ + Load test data for evaluation. + + Parameters + ---------- + config : object + Configuration object. + model_version_path : str + Path to the model version. + eval_path : str + Path to evaluation directory. + n_test : int, default = -1 + Number of test samples to load, by default -1 (load all). + + Returns + ------- + atoms_list + List of ase.Atoms containing the test data. + """ + log.info("Running Input Pipeline") os.makedirs(eval_path, exist_ok=True) @@ -67,6 +87,27 @@ def load_test_data( def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=False): + """ + Perform predictions on the test dataset. + + Parameters + ---------- + model : + Trained model. + params : + Model parameters. + Metrics : + Collection of metrics. + loss_fn : + Loss function. + test_ds : + Test dataset. + callbacks : + Callback functions. + is_ensemble : bool, default = False + Whether the model is an ensemble. + """ + callbacks.on_train_begin() _, test_step_fn = make_step_fns( loss_fn, Metrics, model=model, sam_rho=0.0, is_ensemble=is_ensemble @@ -101,6 +142,21 @@ def predict(model, params, Metrics, loss_fn, test_ds, callbacks, is_ensemble=Fal def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): + """ + Evaluate the model using the provided configuration. + + Parameters + ---------- + config_path : str + Path to the configuration file. + n_test : int, default = -1 + Number of test samples to evaluate, by default -1 (evaluate all). + log_file : str, default = "eval.log" + Path to the log file. + log_level : str, default = "error" + Logging level. + """ + setup_logging(log_file, log_level) log.info("Starting model evaluation") config = parse_config(config_path) @@ -110,7 +166,7 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): model_version_path = Path(config.data.directory) / config.data.experiment eval_path = model_version_path / "eval" - callbacks = initialize_callbacks(config.callbacks, eval_path) + callbacks = initialize_callbacks(config, eval_path) loss_fn = initialize_loss_fn(config.loss) Metrics = initialize_metrics(config.metrics) @@ -118,6 +174,7 @@ def eval_model(config_path, n_test=-1, log_file="eval.log", log_level="error"): test_ds = OTFInMemoryDataset( atoms_list, config.model.r_max, + 1, config.data.valid_batch_size, pos_unit=config.data.pos_unit, energy_unit=config.data.energy_unit, diff --git a/apax/train/run.py b/apax/train/run.py index cca77a95..0c1203fc 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -1,6 +1,8 @@ import logging import sys from typing import List +from typing import Union +import os import jax @@ -22,6 +24,17 @@ def setup_logging(log_file, log_level): + """ + Setup logging configuration. + + Parameters + ---------- + log_file : str + Path to the log file. + log_level : str + Logging level. Options: {'debug', 'info', 'warning', 'error', 'critical'}. + """ + log_levels = { "debug": logging.DEBUG, "info": logging.INFO, @@ -44,6 +57,20 @@ def setup_logging(log_file, log_level): def initialize_loss_fn(loss_config_list: List[LossConfig]) -> LossCollection: + """ + Initialize loss functions based on configuration. + + Parameters + ---------- + loss_config_list : List[LossConfig] + List of loss configurations. + + Returns + ------- + LossCollection + Collection of initialized loss functions. + """ + log.info("Initializing Loss Function") loss_funcs = [] for loss in loss_config_list: @@ -52,6 +79,24 @@ def initialize_loss_fn(loss_config_list: List[LossConfig]) -> LossCollection: def initialize_datasets(config: Config): + """ + Initialize training and validation datasets based on the provided configuration. + + Parameters + ---------- + config : Config + Configuration object all parameters. + + Returns + ------- + train_ds : Dataset + Training dataset. + val_ds : Dataset + Validation dataset. + ds_stats : Dict[str, Tuple[float, float]] + Dictionary containing scale and shift parameters for normalization. + """ + train_raw_ds, val_raw_ds = load_data_files(config.data) Dataset = dataset_dict[config.data.ds_type] @@ -88,7 +133,16 @@ def initialize_datasets(config: Config): return train_ds, val_ds, ds_stats -def run(user_config, log_level="error"): +def run(user_config: Union[str, os.PathLike, dict], log_level="error"): + """ + Starts the training of a model with parameters provided by a the config. + + Parameters + ---------- + + user_config : str | os.PathLike | dict + training config full exmaple can be finde :ref:`here `: + """ config = parse_config(user_config) seed_py_np_tf(config.seed) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index 6622c9f1..dc39346c 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -35,6 +35,43 @@ def fit( is_ensemble=False, data_parallel=True, ): + """ + Trains the model using the provided training dataset. + + Parameters + ---------- + state : + The initial state of the model. + train_ds : InMemoryDataset + The training dataset. + loss_fn : + The loss function to be minimized. + Metrics metrics.Collection : + Collection of metrics to evaluate during training. + callbacks : list + List of callback functions to be executed during training. + n_epochs : int + Number of epochs for training. + ckpt_dir: + Directory to save checkpoints. + ckpt_interval : int, default = 1 + Interval for saving checkpoints. + val_ds : InMemoryDataset, default = None + Validation dataset. + sam_rho : float, default = 0.0 + Rho parameter for Sharpness-Aware Minimization. + patience : int, default = None + Patience for early stopping. + disable_pbar : bool, default = False + Whether to disable progress bar for epochs.. + disable_batch_pbar : bool, default = True + Whether to disable progress bar for batches. + is_ensemble : bool, default = False + Whether the model is an ensemble. + data_parallel : bool, default = True + Whether to use data parallelism. + """ + log.info("Beginning Training") callbacks.on_train_begin() @@ -183,8 +220,11 @@ def fit( def global_norm(updates) -> jnp.ndarray: - """Returns the l2 norm of the input. - Args: + """ + Returns the l2 norm of the input. + + Parameters + ---------- updates: A pytree of ndarrays representing the gradient. """ norm = jax.tree_map(lambda u: jnp.sqrt(jnp.sum(jnp.square(u))), updates) From 43cc2367b922101b5b8ff91e81c9d7c799fb5ec6 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:14:21 +0200 Subject: [PATCH 170/192] link full config --- docs/source/_tutorials/05_Full_Config.nblink | 3 --- docs/source/_tutorials/index.rst | 3 +-- docs/source/getting_started/full_config.rst | 11 +++++++++++ docs/source/getting_started/index.rst | 1 + 4 files changed, 13 insertions(+), 5 deletions(-) delete mode 100644 docs/source/_tutorials/05_Full_Config.nblink create mode 100644 docs/source/getting_started/full_config.rst diff --git a/docs/source/_tutorials/05_Full_Config.nblink b/docs/source/_tutorials/05_Full_Config.nblink deleted file mode 100644 index e191e9d6..00000000 --- a/docs/source/_tutorials/05_Full_Config.nblink +++ /dev/null @@ -1,3 +0,0 @@ -{ - "path": "../../../examples/05_Full_Config.ipynb" -} diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index 688967c5..2231071d 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -7,5 +7,4 @@ Tutorials 01_Model_Training 02_Molecular_dynamics 03_Transfer_Learning - 04_Batch_Data_Selection - 05_Full_Config + 04_Batch_Data_Selection \ No newline at end of file diff --git a/docs/source/getting_started/full_config.rst b/docs/source/getting_started/full_config.rst new file mode 100644 index 00000000..3b0cade1 --- /dev/null +++ b/docs/source/getting_started/full_config.rst @@ -0,0 +1,11 @@ + +.. _config: +====== +Config +====== + +Full config can be downloaded :download:`here <../../../apax/cli/templates/train_config_full.yaml>`. + +.. include:: ../../../apax/cli/templates/train_config_full.yaml + :literal: + diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index 7970eb5d..beb0aa86 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -5,3 +5,4 @@ Getting Started :maxdepth: 2 install + full_config \ No newline at end of file From eb4b7fb301184cb2c0ea7f5d0d7479569beaa4de Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:15:14 +0200 Subject: [PATCH 171/192] exlude members of base pydantic class --- docs/source/modules/config.rst | 47 ++++++++++++++++++++++++++++++++++ docs/source/modules/train.rst | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/source/modules/config.rst b/docs/source/modules/config.rst index 4ac0ec5b..98f331fe 100644 --- a/docs/source/modules/config.rst +++ b/docs/source/modules/config.rst @@ -8,6 +8,48 @@ Training Configuration .. autoclass:: apax.config.train_config.Config :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.DataConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.ModelConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.OptimizerConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.MetricsConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.LossConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.CheckpointConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.TrainProgressbarConfig + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.CSVCallback + :members: + :exclude-members: model_config , model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.TBCallback + :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.train_config.MLFlowCallback + :members: + :exclude-members: model_config, model_computed_fields, model_fields + Molecular Dynamics Configuration @@ -15,3 +57,8 @@ Molecular Dynamics Configuration .. autoclass:: apax.config.md_config.MDConfig :members: + :exclude-members: model_config, model_computed_fields, model_fields + +.. autoclass:: apax.config.md_config.NPTOptions + :members: + :exclude-members: model_config, model_computed_fields, model_fields \ No newline at end of file diff --git a/docs/source/modules/train.rst b/docs/source/modules/train.rst index d50dc2dc..9ba418df 100644 --- a/docs/source/modules/train.rst +++ b/docs/source/modules/train.rst @@ -18,6 +18,6 @@ Training .. automodule:: apax.train.run :members: - + .. automodule:: apax.train.trainer :members: From bd9fb51f8fde3d56ba93c606e15534b446d8a2b7 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:15:49 +0200 Subject: [PATCH 172/192] updated example 01 --- examples/01_Model_Training.ipynb | 95 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 48248ffc..fc656eb2 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -21,12 +21,12 @@ "\n", "## Acquiring a dataset\n", "\n", - "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://sgdml.org/?datasetID=benzene2018_dft). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mod_md_datasets` function in order to be readable." + "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/ethanol_ccsd_t.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mod_md_datasets` function in order to be readable." ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -78,6 +78,8 @@ "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", "\u001b[2m│\u001b[0m \u001b[1;36mmd \u001b[0m\u001b[1;36m \u001b[0m Starts performing a molecular dynamics simulation (currently only \u001b[2m│\u001b[0m\n", "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m NHC thermostat) with parameters provided by a configuration file. \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36mschema \u001b[0m\u001b[1;36m \u001b[0m Generating JSON schemata for autocompletion of train/md inputs in \u001b[2m│\u001b[0m\n", + "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m VSCode. \u001b[2m│\u001b[0m\n", "\u001b[2m│\u001b[0m \u001b[1;36mtemplate \u001b[0m\u001b[1;36m \u001b[0m Create configuration file templates. \u001b[2m│\u001b[0m\n", "\u001b[2m│\u001b[0m \u001b[1;36mtrain \u001b[0m\u001b[1;36m \u001b[0m Starts the training of a model with parameters provided by a \u001b[2m│\u001b[0m\n", "\u001b[2m│\u001b[0m \u001b[1;36m \u001b[0m configuration file. \u001b[2m│\u001b[0m\n", @@ -103,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -122,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -153,7 +155,7 @@ " data_path: project/ethanol_ccsd_t-train_mod.xyz\n", " directory: project/models\n", " energy_unit: kcal/mol\n", - " experiment: benzene_dft_cli\n", + " experiment: ethanol_ccsd_t_cli\n", " n_train: 990\n", " n_valid: 10\n", " pos_unit: Ang\n", @@ -181,7 +183,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -197,7 +199,7 @@ " \"n_train\": 990,\n", " \"n_valid\": 10,\n", " \"valid_batch_size\": 1,\n", - " \"experiment\": \"benzene_dft_cli\",\n", + " \"experiment\": \"ethanol_ccsd_t_cli\",\n", " \"directory\": \"project/models\",\n", " \"data_path\": str(train_file_path),\n", " \"test_data_path\": str(test_file_path),\n", @@ -216,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -243,29 +245,27 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "INFO | 15:03:19 | Initializing Callbacks\n", - "INFO | 15:03:19 | Initializing Loss Function\n", - "INFO | 15:03:19 | Initializing Metrics\n", - "INFO | 15:03:19 | Running Input Pipeline\n", - "INFO | 15:03:19 | Read data file project/ethanol_ccsd_t-train_mod.xyz\n", - "INFO | 15:03:19 | Loading data from project/ethanol_ccsd_t-train_mod.xyz\n", - "INFO | 15:03:19 | Precomputing neighborlists\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 990/990 [00:00<00:00, 14011.30it/s]\n", - "INFO | 15:03:20 | Computing per element energy regression.\n", - "INFO | 15:03:26 | Precomputing neighborlists\n", - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 8937.36it/s]\n", - "INFO | 15:03:26 | Initializing Model\n", - "INFO | 15:03:26 | initializing 1 models\n", - "INFO | 15:03:32 | Initializing Optimizer\n", - "INFO | 15:03:32 | Beginning Training\n", - "Epochs: 100%|████████████████████████████████████| 100/100 [02:31<00:00, 1.52s/it, val_loss=0.0694]\n" + "INFO | 12:22:53 | Running on [cuda(id=0)]\n", + "INFO | 12:22:53 | Initializing Callbacks\n", + "INFO | 12:22:53 | Initializing Loss Function\n", + "INFO | 12:22:53 | Initializing Metrics\n", + "INFO | 12:22:53 | Running Input Pipeline\n", + "INFO | 12:22:53 | Read data file project/ethanol_ccsd_t-train_mod.xyz\n", + "INFO | 12:22:53 | Loading data from project/ethanol_ccsd_t-train_mod.xyz\n", + "INFO | 12:22:54 | Computing per element energy regression.\n", + "INFO | 12:22:54 | Initializing Model\n", + "INFO | 12:22:54 | initializing 1 models\n", + "INFO | 12:23:03 | Initializing Optimizer\n", + "INFO | 12:23:04 | Beginning Training\n", + "Epochs: 100%|█████████████████████████████████████| 100/100 [00:48<00:00, 2.07it/s, val_loss=0.105]\n", + "INFO | 12:23:52 | Finished training\n" ] } ], @@ -296,16 +296,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|██████████████████████████████████████████| 990/990 [00:00<00:00, 8954.80it/s]\n", - "Precomputing NL: 100%|████████████████████████████████████████████| 10/10 [00:00<00:00, 4902.18it/s]\n", - "Epochs: 100%|████████████████████████████████████| 100/100 [02:32<00:00, 1.52s/it, val_loss=0.0694]\n" + "Epochs: 100%|█████████████████████████████████████| 100/100 [00:47<00:00, 2.12it/s, val_loss=0.105]\n" ] } ], @@ -318,7 +316,7 @@ "\n", "config_updates = {\n", " \"data\": {\n", - " \"experiment\": \"benzene_dft_script\",\n", + " \"experiment\": \"ethanol_ccsd_t_script\",\n", " },\n", "}\n", "\n", @@ -329,12 +327,12 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { "data": { - "image/png": "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5f7772fo0KEujKxiOI5ZTAdVtW2BKoRwG061LP7www/07du30PFHHnmEH374AYC+ffty8ODBa4uuCvDJb1nMs7csSje0EO5s7dq1jB8/HoPB4HA8MjKS06dPuyiqiuOwzqJqBVOmawMSQlQ6p5JFDw8PNmzYUOj4hg0b8PDwAMBqtdp/vp4VdEObKNjuL8eF0QghXM1qtWKxWAodP3XqFL6+vi6IqGIFeOnJxoi54J8LmeQihNtxqhv6mWeeYdiwYWzfvt2+luLWrVv54osveOmllwD4888/adWqVbkF6ioFLYvZSv43a1OGC6MRQrjanXfeydSpU+17QSuKQkZGBhMnTqR3794ujq78BXgaAIUM1ZMAJTN/+ZxwV4clhKhETiWL48ePJyoqio8//phvvvkGgIYNGzJjxgz69esHwLBhw3jqqafKL1IXKUgWsxQf24EcGeAthDt7//336dGjB02aNCEnJ4d+/fpx+PBhgoOD+f77710dXrnz97L1qqSrXrZkUWZEC+F2ytwNbTabee211+jSpQsbN24kOTmZ5ORkNm7caE8UATw9PUvshl6zZg333HMPNWrUQFEUFixYUOLzV61axc0334zRaKR+/foVvhert1ELQLribTuQnVKhzxNCVG21atVi9+7dvPzyy4wePZro6Gjeeustdu7cSUhIiKvDK3e+Rh2KAhmyP7QQbqvMLYs6nY533nmHAQMGXPPDMzMzadmyJYMHD+aBBx4osfzx48e56667GDZsGN999x3Lly/niSeeIDw8nB49elxzPEUpGLOYRn6yKC2LQrg9nU5H//796d+/v6tDqXAajYK/p540s+ziIoS7cqob+vbbb2f16tVERkZe08N79epFr169Sl1++vTpREVF8f777wPQuHFj1q1bx5QpU4pNFnNzc8nNvbzcTVpa2So63/xkMVXN/1YtyaIQbi0uLo7Q0FAGDx7scHzmzJmcP3+eF1980UWRVZwATz3paQV1oCSLQrgbp5LFXr16MXbsWPbs2UPr1q3x9vZ2ON+nT59yCe7fNm7cSPfu3R2O9ejRg1GjRhV7TVxcHJMmTXL6mQUti8nWgpbFFKfvJYS4/n322WfMmTOn0PGmTZvyyCOP3JDJor+XgYw02fJPCHflVLL49NNPA/DBBx8UOqcoSpHLSpSHxMREQkNDHY6FhoaSlpZGdnY2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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAosAAAHrCAYAAACn9tfQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACm1UlEQVR4nOzdd3xT9frA8c/J7N50AIUWUJCNLBkKKBvF9bsOUMCBFwUVUBEUwXWp46roBcUFuFAUQUQURTayC0X2hpbSBaV7pE3O74+0gdiWDpqkkOf9euXV5uTknCe93K9Pnu9SVFVVEUIIIYQQohwaVwcghBBCCCHqLkkWhRBCCCFEhSRZFEIIIYQQFZJkUQghhBBCVEiSRSGEEEIIUSFJFoUQQgghRIUkWRRCCCGEEBWSZFEIIYQQQlRIkkUhhBBCCFEhSRaFEC4TFRWFoigoisLTTz99yXPffvtt27k6nc5JEVbu5MmTKIpCVFSUq0MRQgiHkGRRCFEnfPPNN5hMpgpfnzt3bq3eT5I8IYSoGkkWhRAu16lTJ86dO8fSpUvLfX3Tpk0cPHiQzp07OzmyyjVo0IADBw6watUqV4cihBAOIcmiEMLlHn74YaDi6uHnn39ud15dotfradGiBU2bNnV1KEII4RCSLAohXK5NmzZ06tSJP/74g8TERLvXcnJy+P7772nYsCH9+/ev8BrFxcV89tln9O7dm6CgIIxGI9HR0Tz++OMkJCTYnTtq1Ciio6MBOHXqlG0sZOmj1Msvv4yiKLz88svEx8fzyCOPEBkZiV6vZ9SoUUDl3dl5eXnMnDmTnj17EhgYiNFopHHjxtx2220sWLDA7tzMzEymTp1KmzZt8Pb2xmg0Ur9+fXr06MG0adMoKiqq6p9UCCFqTd0ZJS6EcGsPP/wwO3bsYP78+bz44ou2499//z05OTk8/fTTaDTlf7/Nzs5m6NChrF27Fh8fHzp27Ei9evXYs2cPc+bM4YcffmDlypV06NABgJ49e5KTk8OPP/6It7c3//d//3fJ2I4cOUKHDh0wGAz06NEDVVUJCQmp9DMlJCQwcOBA9u/fj5eXFz169CA4OJjExEQ2bNjAnj17GDZsGGBNKnv27MnevXupV68et9xyC97e3iQnJ3Pw4EE2bdrExIkTCQgIqOJfVAghaokqhBAu0rhxYxVQN2zYoGZkZKienp5qs2bN7M7p0aOHqiiKeuzYMfXEiRMqoGq1Wrtzhg0bpgLqrbfeqqakpNi99t5776mAes0116jFxcW246XXaty4cYXxTZ8+XQVUQH3ggQfUgoKCMudUdB2z2ax26tRJBdT+/furqampdq/n5+ery5cvtz3/4osvVEAdNGiQajKZylxr7dq1amFhYYWxCiGEo0g3tBCiTvD39+euu+7i6NGjrFu3DoBDhw7x119/0atXL5o0aVLu+w4cOMC3335L/fr1WbBgAaGhoXavjx8/nsGDB3PkyBF+++23GsUWFBTErFmzMBqNVX7PsmXL2LFjBxEREfz444/Uq1fP7nUPDw8GDx5se56SkgJAv3790Ov1dudqNBp69eqFwWCoUfxCCHE5JFkUQtQZ/5zoUvrzUhNbfv31V1RVZdCgQfj6+pZ7Tu/evQHrrOqa6Nu3L/7+/tV6z4oVKwAYNmwYPj4+lZ5fOtP7rbfe4ssvvyQ9Pb36gQohhANIsiiEqDP69OlDdHQ0ixYt4vz583z55Zf4+fldckzh8ePHAeuM6X9OVCl9TJo0CYC0tLQaxVWTtRhPnToFQIsWLap0fu/evXn++edJTU1l5MiRhISE0Lx5cx5++GGWLl2KxWKpdgxCCFEbZIKLEKLOUBSFUaNGMX36dEaOHElycjKPPfYYnp6eFb6nNIlq37497dq1u+T1u3btWqO4LnX/2vTGG28wZswYli1bxsaNG/nrr7+YN28e8+bNo3PnzqxZswZvb2+nxCKEEKUkWRRC1CmjRo3ilVdeYdmyZUDlaytGRkYC0KNHD2bNmuXw+KqqUaNGABw8eLBa74uKiuLJJ5/kySefBGD79u088MADbN++nbfeeotXXnml1mMVQohLkW5oIUSd0qhRI26//XaCg4O54YYbKq0GDho0CICff/6ZgoKCKt+ndLJIcXFxzYO9hIEDBwLw7bffkpubW+PrdO7cmSeeeAKAuLi42ghNCCGqRZJFIUSds3jxYs6ePcvmzZsrPbdDhw7cfffdJCQkcNddd3Hy5Mky5+Tm5vLNN9/YZhwD1KtXD4PBQHJyskMmkwwdOpQOHTpw5swZ/vWvf3Hu3Dm71wsKCuxmZy9ZsoT169eXGZtYVFRkmyzTuHHjWo9TCCEqI93QQogr3rx588jIyOC3336jefPmtGvXjujoaFRV5eTJk+zevRuTycSBAwcICwsDrNv0DR06lEWLFtG+fXt69uyJl5cXAJ999tllx6TRaFiyZAkDBgzgt99+o1GjRvTs2dO2KPfu3bsJCAiwJbfr1q3j/fffJyQkhA4dOhAaGkp2djZbtmwhNTWVBg0a2CbqCCGEM0myKIS44vn6+vLHH3+wcOFCvv76a2JjY4mLi8PPz4+IiAiGDx/O0KFDy+zf/PHHHxMcHMxvv/3GokWLbNvp1UayCNZK4I4dO/jwww9ZtGgRmzdvxmQyER4eTq9evWy7t4B1rKanpycbN25k//79rFu3Dn9/fxo1asT48eN57LHHCA4OrpW4hBCiOhRVVVVXByGEEEIIIeomGbMohBBCCCEqJMmiEEIIIYSokCSLQgghhBCiQpIsCiGEEEKICkmyKIQQQgghKiTJohBCCCGEqJAki0IIIYQQokKSLAohhBBCiApJsiiEEEIIISokyaIQQgghhKiQJItCCCGEEKJCkiwKIYQQQogKXXHJ4kcffUTbtm3x8/PDz8+Pbt268dtvv7k6LCGEEEKIq5Kiqqrq6iCqY9myZWi1Wq655hpUVeWLL77g7bffZteuXbRq1crV4QkhhBBCXFWuuGSxPEFBQbz99ts88sgjlZ5rsVg4c+YMvr6+KIrihOiEEHWJqqpkZ2dTv359NJorrnPlskj7J4R7q2n7p3NgTA5nNpv54YcfyM3NpVu3buWeU1hYSGFhoe15YmIiLVu2dFaIQog6KiEhgYYNG7o6DKc6c+YMkZGRrg5DCOFi1W3/rshkcc+ePXTr1o2CggJ8fHxYsmRJhQlgTEwMr7zySpnjCQkJ+Pn5OTpUIUQdk5WVRWRkJL6+vq4OxelKP7O0f0K4p5q2f1dkN7TJZCI+Pp7MzEwWLVrEZ599xrp168pNGP9ZWSz9Q2VmZkpjKYQbysrKwt/f3y3bAHf+7EKImrcBV2Rl0WAw0KxZMwA6duzI9u3bef/99/n444/LnGs0GjEajc4OUQghhBDiqnBVjO62WCx21UMhhBBCCFE7rrjK4pQpUxg0aBCNGjUiOzubBQsWsHbtWn7//XdXhyaEEEIIcdW54pLF1NRURowYQVJSEv7+/rRt25bff/+dfv36OeaGWz8Gswk6PQwGb8fcQwgh6hpVhW2fQnEBdH4UDF6ujkgI4SJXXLL4+eefO/eGv78IliJodZcki0II96Eo8PsUsBRDm/+TZFEIN3ZVjFl0KE1JPm0pdm0cQgjhbDoP68+ifNfGIYRwKUkWK6PVW39KsiiEcDelyWKxTCAUwp1JsliZ0sqiuci1cQghhLPZkkWpLArhziRZrIytsijJohDCzeilsiiEkGSxcpqSZFEqi0IIdyNjFoUQSLJYOa1McBFCuCkZsyiEQJLFyslsaCGEu9J7Wn/KmEUh3Joki5WRbmghhLvSGa0/pbIohFuTZLEytm5oSRaFEG5GxiwKIZBksXK2yqJ0Qwsh3IyMWRRCIMli5WTpHCGEu9LLOotCCEkWKydjFoUQ7koqi0IIJFmsnEZr/WkxuzYOIYRwNhmzKIRAksXKSTe0EMJdSWVRCIEki5WTbmghhLuSMYtCCCRZrJwsnSOEcFdSWRRCIMli5WTpHCGEu5Ixi0IIJFmsnIxZFEK4K6ksCiGQZLFysje0EMJdyd7QQggkWaxcabIo3dBCCHcje0MLIZBksXLSDS2EcFe6ksqijFkUwq1JslgZWTpHCOGupLIohECSxcrJ0jlCCHclYxaFEEiyWDlZOkcI4a6ksiiEQJLFymmksiiEcFO2MYsFro1DCOFSkixWxjbBRSqLQgg3Y6ssSrIohDuTZLEysnSOEMJdlY5ZNBeCxeLaWIQQLiPJYmVk6RwhhLsqrSyCNWEUQrglSRYrI0vnCCEcYP369dx2223Ur18fRVH46aefLnn+2rVrURSlzCM5OdlxQZaOWQRZa1EINybJYmVk6RwhhAPk5ubSrl07Zs+eXa33HTp0iKSkJNsjNDTUQRFibf8UrfV3mREthNvSuTqAOk/GLAohHGDQoEEMGjSo2u8LDQ0lICCg9gOqiN4TTDmy1qIQbkwqi5XRyGxoIUTd0b59eyIiIujXrx9//fXXJc8tLCwkKyvL7lFtpeMWZfkcIdyWJIuVkQkuQog6ICIigjlz5vDjjz/y448/EhkZSe/evdm5c2eF74mJicHf39/2iIyMrP6NS8ctyvI5Qrgt6YaujHRDCyHqgObNm9O8eXPb8+7du3Ps2DHee+89vvrqq3LfM2XKFCZOnGh7npWVVf2EUdZaFMLtSbJYGaksCiHqqC5durBx48YKXzcajRiNxgpfrxK9VBaFcHfSDV0ZWTpHCFFHxcXFERER4dibyJhFIdyeVBYrI3tDCyEcICcnh6NHj9qenzhxgri4OIKCgmjUqBFTpkwhMTGRL7/8EoCZM2cSHR1Nq1atKCgo4LPPPmP16tX88ccfjg1UxiwK4facniwePXqUY8eOcdNNN+Hp6YmqqiiK4uwwqs62zqLZtXEIIa4qO3bsoE+fPrbnpWMLR44cyfz580lKSiI+Pt72uslk4plnniExMREvLy/atm3Ln3/+aXcNh5Axi0K4Pacli+fOnePee+9l9erVKIrCkSNHaNKkCY888giBgYG88847zgqleqQbWgjhAL1790ZV1Qpfnz9/vt3zSZMmMWnSJAdHVQ4ZsyiE23PamMUJEyag0+mIj4/Hy8vLdvzee+9lxYoVzgqj+mSCixDCncmYRSHcntMqi3/88Qe///47DRs2tDt+zTXXcOrUKWeFUX2ydI4Qwp3JmEUh3J7TKou5ubl2FcVS6enpl7+0gyNJZVEI8Q/Hjh1j6tSp3H///aSmpgLw22+/sW/fPhdH5gAyZlEIt+e0ZPHGG2+0zeoDUBQFi8XCW2+95fgB2pfDVlmUZFEIAevWraNNmzZs3bqVxYsXk5OTA8Du3buZPn26i6NzABmzKITbc1o39FtvvcUtt9zCjh07MJlMTJo0iX379pGenl7p/qYuZdsbWmZDCyFg8uTJvP7660ycOBFfX1/b8ZtvvplZs2a5MDIHkTGLQrg9p1UWW7duzeHDh+nZsye33347ubm53HXXXezatYumTZtW+ToxMTF07twZX19fQkNDueOOOzh06JDjAtfKOotCiAv27NnDnXfeWeZ4aGgoZ8+edUFEDiZjFoVwe05dZ9Hf358XX3zxsq6xbt06xo4dS+fOnSkuLuaFF16gf//+7N+/H29v71qK9CKydI4Q4iIBAQEkJSURHR1td3zXrl00aNDARVE5kIxZFMLtOX1R7ry8POLj4zGZTHbH27ZtW6X3/3OZnfnz5xMaGkpsbCw33XRTrcVpc/EEF1WFuryAuBDC4e677z6ef/55fvjhB9vY67/++otnn32WESNGuDq82idjFoVwe05LFtPS0njooYf47bffyn3dbK7ZmMDMzEwAgoKCyn29sLCQwsJC2/OsrKzq3UBz0Z/IYr7QLS2EcEszZsxg7NixREZGYjabadmyJWazmWHDhjF16lRXh1f7dB7WnzJmUQi35bQxi+PHjycjI4OtW7fi6enJihUr+OKLL7jmmmv4+eefa3RNi8XC+PHj6dGjB61bty73nJiYGPz9/W2PyMjI6t3ELlmUrmgh3J3BYODTTz/l+PHj/PLLL3z99dccPHiQr776Cq1W6+rwal9psiiVRSHcltPKZKtXr2bp0qV06tQJjUZD48aN6devH35+fsTExDBkyJBqX3Ps2LHs3buXjRs3VnjOlClTbHuugrWyWK2EsbQbGsAiC3MLIawiIyNt1cU9e/Zw/vx5AgMDXR1W7dNLsiiEu3PqotyhoaEABAYGkpaWBkCbNm3YuXNnta83btw4fvnlF9asWVNmV5iLGY1G/Pz87B7VorkoWZRJLkK4vfHjx/P5558D1uEzvXr14vrrrycyMpK1a9e6NjhHkMqiEG7Pacli8+bNbUvctGvXjo8//pjExETmzJlDREREla+jqirjxo1jyZIlrF69usyMxFqnuahbSSqLQri9RYsW0a5dOwCWLVvG8ePHOXjwIBMmTLjs1R7qJBmzKITbc1o39NNPP01SUhIA06dPZ+DAgXzzzTcYDAbmz59f5euMHTuWBQsWsHTpUnx9fUlOTgasy/J4enrWfuCKYq0uWoqksiiE4OzZs4SHhwPw66+/cs8993Dttdfy8MMP8/7777s4OgeQyqIQbs9pyeIDDzxg+71jx46cOnWKgwcP0qhRI0JCQqp8nY8++giA3r172x2fN28eo0aNqo1Qy9KWJIsywUUItxcWFsb+/fuJiIhgxYoVtjYpLy/v6pzgImMWhXB7LlsHxsvLi+uvv77a71NV1QHRVMK2P7R0Qwvh7h566CHuueceIiIiUBSFvn37ArB161ZatGjh4ugcQCqLQrg9pyWLqqqyaNEi1qxZQ2pqKhaLxe71xYsXOyuU6tPIln9CCKuXX36Z1q1bk5CQwL/+9S+MRusOJ1qtlsmTJ7s4OgeQMYtCuD2nJYvjx4/n448/pk+fPoSFhaFcSTuh2HZxkcqiEAL+7//+r8yxkSNHuiASJyhNFs2FsouVEG7KacniV199xeLFixk8eLCzbll7ZH9oIcRFtm/fXmEvybvvvuuiqBykdMwiWLui9Q6YSCiEqNOcliz6+/vTpEkTZ92udpVu8SeVRSHc3owZM5g6dSrNmzcv00tyRfWYVJVOkkUh3J3TksWXX36ZV155hblz5zpmiRtHksqiEKLE+++/z9y5cx23+kJdo9WDogXVbB23eIU130KIy+e0ZPGee+7h22+/JTQ0lKioKPR6vd3rNdnFxWlsYxYlWRTC3Wk0Gnr06OHqMJxL5wFFuTIjWgg35bRkceTIkcTGxvLAAw9ceRNcSndxkaVzhHB7EyZMYPbs2cycOdPVoTiPXpJFIdyZ05LF5cuX8/vvv9OzZ09n3bL2aGQ2tBDC6tlnn2XIkCE0bdqUli1bluklqdPLgNWUrLUohFtzWrIYGRmJn5+fs25Xu6QbWghR4qmnnmLNmjX06dOH4ODgK6uXpKZkrUUh3JrTksV33nmHSZMmMWfOHKKiopx129ohE1yEECW++OILfvzxR4YMGeLqUJzHVlnMd20cQgiXcOre0Hl5eTRt2hQvL68yXTfp6enOCqX6ZOkcIUSJoKAgmjZt6uownMu2P3Sha+MQQriE05LFK3UwuKqqWBQdWpDKohCCl19+menTpzNv3jy8vLxcHY5z2LqhpbIohDty6mzoqnjjjTcYM2YMAQEBjg2oClRVpdmLvzFHm04/LTJmUQjBBx98wLFjxwgLC7vylgGrKZ1UFoVwZ05LFqtqxowZ3HPPPXUiWVQUBYNWQzElS+dIN7QQbu+OO+5wdQjOJ2MWhXBrdS5ZVFXV1SHY8TRoKTbJOotCCKvp06dX6bxvv/2WoUOH4u3tXe7r69ev5+233yY2NpakpCSWLFlSaSK6du1aJk6cyL59+4iMjGTq1KnO2UlGxiwK4dY0rg6grvPUaykqzamlG1oIUUX//ve/SUlJqfD13Nxc2rVrx+zZs6t0vRMnTjBkyBD69OlDXFwc48eP59FHH+X333+vrZDtmC0qexMzWbE3CdU2ZjHPIfcSQtRtda6yWNd4GrQU55RWFiVZFEJUTWW9JIMGDWLQoEFVvt6cOXOIjo7mnXfeAeC6665j48aNvPfeewwYMOCyYi1PkdnCbbM2oqpwoIePdUvogsxav48Qou6TymIlvAxaGbMohHC5zZs307dvX7tjAwYMYPPmzRW+p7CwkKysLLtHVXnotYT7WSuKGZaSWd+SLArhliRZrISH/qJkUSqLQggXSU5OJiwszO5YWFgYWVlZ5OeXP/EkJiYGf39/2yMyMrJa94wMsiaJZ4tLuqElWRTCLdW5ZPHGG2/E09PT1WHYeOqlsiiEuDJNmTKFzMxM2yMhIaFa729UkiwmFZYki/kZtRyhEOJK4LRksVevXnz55ZcVfgMu9euvvxIREeGkqCrnZdBSZEsWpbIohHCN8PDwMhNmUlJS8PPzq/ALttFoxM/Pz+5RHaXJ4ukCg/WAVBaFcEtOSxY7dOjAs88+S3h4OKNHj2bLli3OuvVlsassytI5Qogqaty4cZkFuy9Ht27dWLVqld2xlStX0q1bt1q7xz81DrYmi6dySz6HJItCuCWnJYszZ87kzJkzzJs3j9TUVG666SZatmzJf//730suL+FqngYtxbJ0jhCiREJCAqdPn7Y937ZtG+PHj+eTTz6xO2/v3r2XHCOYk5NDXFwccXFxgHVpnLi4OOLj4wFrF/KIESNs548ZM4bjx48zadIkDh48yIcffsj333/PhAkTavHT2Ssds3g0q+QLsySLQrglp45Z1Ol03HXXXSxdupTTp08zbNgwXnrpJSIjI7njjjtYvXq1M8OpEk+9liJVJrgIIayGDRvGmjVrAOukk379+rFt2zZefPFFXn311SpfZ8eOHXTo0IEOHToAMHHiRDp06MC0adMASEpKsiWOANHR0SxfvpyVK1fSrl073nnnHT777DOHLJtTqrQb+nhOyRfmggyoYxsnCCEczyXrLG7bto158+bx3XffERoayqhRo0hMTOTWW2/liSee4L///a8rwiqX/ZhF6YYWwt3t3buXLl26APD999/TunVr/vrrL/744w/GjBljS/Yq07t370uuxTh//vxy37Nr164axV0Twd4GvAxaMk0lu9BYiq0LcxvK35VGCHF1clplMTU1lXfeeYfWrVtz4403kpaWxrfffsvJkyd55ZVX+Oyzz/jjjz+YM2eOs0KqEg9JFoUQFykqKsJoNALw559/MnToUABatGhBUlKSK0OrdYqi0CjIizyMWBTpihbCXTmtstiwYUOaNm3Kww8/zKhRo6hXr16Zc9q2bUvnzp2dFVKVeOm1pMo6i0KIEq1atWLOnDkMGTKElStX8tprrwFw5swZgoODXRxd7WsU5MXB5GxMOj88is5bl8/xq+/qsIQQTuS0ZHHVqlXceOONlzzHz8/PNhaorvC028FFkkUh3N2bb77JnXfeydtvv83IkSNp164dAD///LOte/pqUjpuMVfjjQfnpbIohBtyWrJYWaJYV3kadBSV/plk6Rwh3F7v3r05e/YsWVlZBAYG2o4/9thjeHl5uTAyxyhdPicbb4JBkkUh3JDTksUO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No2IiAg8PT3p27cvR44ccWHEF5jNZl566SWio6Px9PSkadOmvPbaa3aby9eV+NevX89tt91G/fr1URSFn376ye71qsSZnp7O8OHD8fPzIyAggEceeYScnBwnfoork7R/ziPtn/NI+1eD9k8VFfruu+9Ug8Ggzp07V923b586evRoNSAgQE1JSXF1aDYDBgxQ582bp+7du1eNi4tTBw8erDZq1EjNycmxnTNmzBg1MjJSXbVqlbpjxw71hhtuULt37+7CqMvatm2bGhUVpbZt21Z9+umnbcfrauzp6elq48aN1VGjRqlbt25Vjx8/rv7+++/q0aNHbee88cYbqr+/v/rTTz+pu3fvVocOHapGR0er+fn5Lozc6j//+Y8aHBys/vLLL+qJEyfUH374QfXx8VHff/992zl1Jf5ff/1VffHFF9XFixergLpkyRK716sS58CBA9V27dqpW7ZsUTds2KA2a9ZMvf/++536Oa400v45j7R/ziXtX/XbP0kWL6FLly7q2LFjbc/NZrNav359NSYmxoVRXVpqaqoKqOvWrVNVVVUzMjJUvV6v/vDDD7ZzDhw4oALq5s2bXRWmnezsbPWaa65RV65cqfbq1cvWWNbl2J9//nm1Z8+eFb5usVjU8PBw9e2337Ydy8jIUI1Go/rtt986I8RLGjJkiPrwww/bHbvrrrvU4cOHq6pad+P/Z2NZlTj379+vAur27dtt5/z222+qoihqYmKi02K/0kj75xzS/jmftH/Vb/+kG7oCJpOJ2NhY+vbtazum0Wjo27cvmzdvdmFkl5aZmQlAUFAQALGxsRQVFdl9jhYtWtCoUaM68znGjh3LkCFD7GKEuh37zz//TKdOnfjXv/5FaGgoHTp04NNPP7W9fuLECZKTk+1i9/f3p2vXri6PHaB79+6sWrWKw4cPA7B79242btzIoEGDgLoff6mqxLl582YCAgLo1KmT7Zy+ffui0WjYunWr02O+Ekj75zzS/jmftH/Vb/90tRf21eXs2bOYzWbCwsLsjoeFhXHw4EEXRXVpFouF8ePH06NHD1q3bg1AcnIyBoOBgIAAu3PDwsJITk52QZT2vvvuO3bu3Mn27dvLvFaXYz9+/DgfffQREydO5IUXXmD79u089dRTGAwGRo4caYuvvH8/ro4dYPLkyWRlZdGiRQu0Wi1ms5n//Oc/DB8+HKDO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OZLKohBup0YTXN555x0GDBhAy5YtKSgoYNiwYRw5coSQkBC+/fbb2o6xTgn1NeJp0HMeX0LIgryz4Bvm6rCEEE42ceLES76+Zs0a2+/vvvtula45aNAgBg0aVO5rqqoyc+ZMpk6dyu233w7Al19+SVhYGD/99BP33XdfFSOvnvoBnmgUSDd7W/+LIWMWhXA7NUoWGzZsyO7du1m4cCG7d+8mJyeHRx55hOHDh9tNeLkaKYpC42Bvzp/zJUTJkkkuQripXbt2Vek8RVFq5X4nTpwgOTmZvn372o75+/vTtWtXNm/eXG6yWFhYSGFhoe15VlZWte+r12qI8PckM0fGLArhrmqULALodDqGDx/O8OHDazOeK0JUsBfp52RGtBDu7OLKoTMkJycDEBZm35MRFhZme+2fYmJieOWVVy773pFBnmRky5hFIdxVjcYsxsTEMHfu3DLH586dy5tvvnnZQdV1USHeFya55J51bTBCCFGBKVOmkJmZaXskJCTU6DoNA70umg2dUXsBCiGuCDVKFj/++GNatGhR5nirVq1qtCD37NmziYqKwsPDg65du7Jt27Yqve+7775DURTuuOOOat/zckQHe1+05Z9McBFCOF54eDgAKSkpdsdTUlJsr/2T0WjEz8/P7lET9XyNZJRuRiDJohBup0bJYnJyMhEREWWO16tXj6SkpGpda+HChUycOJHp06ezc+dO2rVrx4ABA0hNTb3k+06ePMmzzz7LjTfeWK371YaoEG/SkW5oIYTzREdHEx4ebrfxQVZWFlu3bqVbt24OvXewt+HCln8yZlEIt1OjZDEyMpK//vqrzPG//vqL+vXrV+ta7777LqNHj+ahhx6iZcuWzJkzBy8vr3K7uUuZzWaGDx/OK6+8QpMmTaod/+WKCvEiXbV+QzfnpDn9/kKIq1NOTg5xcXHExcUB1kktcXFxxMfHoygK48eP5/XXX+fnn39mz549jBgxgvr16zu8dyXE56LKooxZFMLt1GiCy+jRoxk/fjxFRUXcfPPNAKxatYpJkybxzDPPVPk6JpOJ2NhYpkyZYjum0Wjo27cvmzdvrvB9r776KqGhoTzyyCNs2LDhkveojdmA/1TPx0iu1t96/aw0vC77ikIIATt27KBPnz6256XL84wcOZL58+czadIkcnNzeeyxx8jIyKBnz56sWLECDw8Ph8YV7COV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", "text/plain": [ "
" ] @@ -349,7 +347,7 @@ "import numpy as np\n", "from apax.utils.helpers import load_csv_metrics\n", "\n", - "metrics_path = \"project/models/benzene_dft_script/log.csv\"\n", + "metrics_path = \"project/models/ethanol_ccsd_t_script/log.csv\"\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", "\n", "data_dict = load_csv_metrics(metrics_path)\n", @@ -384,15 +382,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████| 999/999 [00:00<00:00, 14303.45it/s]\n", - "Structure: 100%|███████████████████████████████| 999/999 [00:04<00:00, 220.62it/s, test_loss=0.0866]\n" + "Structure: 100%|███████████████████████████████| 999/999 [00:03<00:00, 280.74it/s, test_loss=0.0838]\n" ] } ], @@ -404,15 +401,14 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Precomputing NL: 100%|█████████████████████████████████████████| 999/999 [00:00<00:00, 14147.08it/s]\n", - "Structure: 100%|███████████████████████████████| 999/999 [00:04<00:00, 239.88it/s, test_loss=0.0866]\n" + "Structure: 100%|███████████████████████████████| 999/999 [00:04<00:00, 214.87it/s, test_loss=0.0837]\n" ] } ], @@ -422,12 +418,12 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -437,7 +433,7 @@ } ], "source": [ - "metrics_path = \"project/models/benzene_dft_script/eval/log.csv\"\n", + "metrics_path = \"project/models/ethanol_ccsd_t_script/eval/log.csv\"\n", "keys = [\"energy_mae\", \"forces_mse\", \"forces_mae\", \"loss\"]\n", "\n", "data_dict = load_csv_metrics(metrics_path)\n", @@ -480,12 +476,19 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ - "# !rm -r project config.yaml eval.log" + "!rm -rf project config.yaml eval.log" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 89345564f4232367fa875db98822ba82a84d8598 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:46:01 +0200 Subject: [PATCH 173/192] update example 02 --- examples/02_Molecular_Dynamics.ipynb | 115 +++++++-------------------- 1 file changed, 27 insertions(+), 88 deletions(-) diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index 1c9ad821..fbae9d32 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -42,20 +42,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-03-13 13:23:46.912545: W external/xla/xla/service/gpu/nvptx_compiler.cc:742] The NVIDIA driver's CUDA version is 11.4 which is older than the ptxas CUDA version (11.8.89). Because the driver is older than the ptxas version, XLA is disabling parallel compilation, which may slow down compilation. You should update your NVIDIA driver or use the NVIDIA-provided CUDA forward compatibility packages.\n", - "Precomputing NL: 100%|█████████████████████████████████████████| 990/990 [00:00<00:00, 23520.26it/s]\n", - "Precomputing NL: 100%|███████████████████████████████████████████| 10/10 [00:00<00:00, 10260.04it/s]\n", - "Epochs: 100%|████████████████████████████████████| 100/100 [00:47<00:00, 2.10it/s, val_loss=0.0693]\n" - ] - } - ], + "outputs": [], "source": [ "from pathlib import Path\n", "from apax.utils.datasets import download_etoh_ccsdt, mod_md_datasets\n", @@ -117,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -160,7 +149,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -179,20 +168,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# plot OH bondlength distribution of the MLMD simulation\n", "traj = Trajectory('example.traj')\n", @@ -224,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -251,7 +229,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -284,18 +262,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32mSuccess!\u001b[0m\n", - "md_config.yaml is a valid MD config.\n" - ] - } - ], + "outputs": [], "source": [ "!apax validate md md_config.yaml" ] @@ -311,28 +280,9 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO | 13:39:53 | reading structure\n", - "INFO | 13:39:53 | Unable to initialize backend 'rocm': NOT_FOUND: Could not find registered platform with name: \"rocm\". Available platform names are: CUDA\n", - "INFO | 13:39:53 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", - "2024-03-13 13:39:54.071387: W external/xla/xla/service/gpu/nvptx_compiler.cc:742] The NVIDIA driver's CUDA version is 11.4 which is older than the ptxas CUDA version (11.8.89). Because the driver is older than the ptxas version, XLA is disabling parallel compilation, which may slow down compilation. You should update your NVIDIA driver or use the NVIDIA-provided CUDA forward compatibility packages.\n", - "INFO | 13:39:54 | initializing model\n", - "INFO | 13:39:54 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/etoh_md/best\n", - "INFO | 13:39:54 | Initializing new trajectory file at md/md.h5\n", - "INFO | 13:39:54 | initializing simulation\n", - "INFO | 13:39:57 | running simulation for 5.0 ps\n", - "Simulation: 0%| | 0/10000 [00:00" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import znh5md\n", "\n", "atoms = znh5md.ASEH5MD(\"md/md.h5\").get_atoms_list()\n", - "print(atoms[0].numbers)\n", "plot_bondlength_distribution(atoms, indices=[2, -1])" ] }, @@ -385,11 +316,19 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rm: cannot remove 'project/models/etoh_md/.nfs00000000c5aa84b000000020': Device or resource busy\n" + ] + } + ], "source": [ - "# !rm -rf project md config.yaml example.traj md_config.yaml" + "!rm -rf project md config.yaml example.traj md_config.yaml" ] }, { From 7dbc6d8836c4424ca16d68fd14e3570a0731bebf Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Tue, 9 Apr 2024 21:46:39 +0200 Subject: [PATCH 174/192] update example 02 --- examples/02_Molecular_Dynamics.ipynb | 99 +++++++++++++++++++++------- 1 file changed, 74 insertions(+), 25 deletions(-) diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index fbae9d32..b18ea941 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -42,9 +42,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Epochs: 100%|█████████████████████████████████████| 100/100 [00:47<00:00, 2.09it/s, val_loss=0.105]\n" + ] + } + ], "source": [ "from pathlib import Path\n", "from apax.utils.datasets import download_etoh_ccsdt, mod_md_datasets\n", @@ -106,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -149,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -168,9 +176,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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SdE111yj9evXt+iYFkR6DUpLS3XttdeqW7duyszM1MiRI7Vv375oT6PZovE9cNbcuXMVFxenyZMnR2HkkRONNfjuu+907733KiMjQ6mpqRowYIA+/fTTaE6jRSK9BnV1dZo5c6ZycnKUmpqqK6+8Uk899VST/uZIa9u0aZPuvPNOZWdnKy4uTu+8884FX/PRRx9p8ODBSk5O1m9+8xstW7bsvH3a0rkwGmvQ1s6F0fo+OKvF50PXgaxatcolJSW5119/3e3evduNHz/epaenu+rq6kb3nz59usvOznbr1q1zX375pXv55ZddSkqK2759e7OPGWvRWIP8/Hy3dOlS9/nnn7udO3e622+/3fXq1csdP368tabVZNGY/1lbt251vXv3dldffbWbNGlSlGfSfNFYgyNHjrjLL7/c3XfffW7Lli3u4MGD7oMPPnD//ve/W2taYYnGGsyZM8dlZGS4tWvXuq+++sqtXr3ade3a1b344outNa0m+/vf/+4ee+wx9/bbbztJbs2aNb+6/8GDB13nzp3d1KlT3Z49e9zChQtdQkKCW79+fWiftnYujMYatKVzoXPRWYOzInE+7FCBct1117mioqLQv+vq6lx2drYrLS1tdP8ePXq4l156qcG2u+66yxUWFjb7mLEWjTU4V01NjZPkNm7cGJlBR1C05n/s2DHXp08fV1ZW5m666SbTgRKNNXj00UfdjTfeGJ0BR0E01qCgoMA98MADv7qPRU35wTR9+nR31VVXNdh2zz33uPz8/NC/29q58JcitQbnsnwuPFck1yBS58MO8yueU6dOqbKyUnl5eaFt8fHxysvLU0VFRaOvqa2tVUpKSoNtqamp+vjjj5t9zFiKxho0JhAISJK6d+8egVFHTjTnX1RUpIKCggbHtihaa/Duu+9q6NChuvvuu5WZmalBgwbp1Vdfjc4kWihaa3DDDTeovLxc+/fvlyR99tln+vjjj3XbbbdFYRatq6Ki4rzv7fz8/NB6tbVzYXNcaA0aY/Vc2FxNXYNInQ87TKD8+OOPqqurO+9OtV6vV36/v9HX5Ofna/78+Tpw4IDq6+tVVlamt99+W99//32zjxlL0ViDc9XX12vy5MkaPny4+vfvH/E5tES05r9q1Spt375dpaWlUR1/JERrDQ4ePKjFixerT58++uCDDzRx4kQ99NBDWr58eVTn0xzRWoOSkhKNHj1affv2VadOnTRo0CBNnjxZhYWFUZ1Pa/D7/Y2uVzAY1H/+8582dy5sjgutwbksnwubqylrEMnzYYcJlOZ48cUX1adPH/Xt21dJSUkqLi7W/fffr/j4jrNs4a5BUVGRPv/8c61ataqVRxodF5p/VVWVJk2apBUrVpz3/7Dbi6Z8D9TX12vw4MF65plnNGjQIE2YMEHjx4/XkiVLYjjyyGnKGrz55ptasWKFVq5cqe3bt2v58uV67rnnTEYaoq+9nQubItLnww7zk/biiy9WQkKCqqurG2yvrq5WVlZWo6+55JJL9M477+jEiRP65ptv9MUXX6hr16664oormn3MWIrGGvxScXGx1q5dqw8//FCXXXZZVObQEtGYf2VlpWpqajR48GAlJiYqMTFRGzdu1IIFC5SYmKi6urqozysc0foe6NGjh3Jzcxu8rl+/fjp06FDkJ9FC0VqDadOmha6iDBgwQGPGjNGUKVPaxJW1C8nKymp0vTwej1JTU9vcubA5LrQGv2T9XNhcF1qDSJ8PO0ygJCUlaciQISovLw9tq6+vV3l5uXw+36++NiUlRZdeeqnOnDmjt956S7///e9bfMxYiMYaSJJzTsXFxVqzZo02bNignJycqM2hJaIx/xEjRmjXrl3auXNn6DF06FAVFhZq586dSkhIiOqcwhWt74Hhw4ef93HK/fv36/LLL4/sBCIgWmvw888/n3dlMSEhQfX19ZGdQAz4fL4G6yVJZWVlofVqa+fC5rjQGkht51zYXBdag4ifD5v11to2atWqVS45OdktW7bM7dmzx02YMMGlp6c7v9/vnHNuzJgxrqSkJLT/5s2b3VtvveW+/PJLt2nTJnfzzTe7nJwc99NPPzX5mNZEYw0mTpzo0tLS3EcffeS+//770OPnn39u7eldUDTmfy7rn+KJxhps3brVJSYmujlz5rgDBw64FStWuM6dO7s33nijtafXJNFYg7Fjx7pLL7009DHjt99+21188cVu+vTprT29Czp27JjbsWOH27Fjh5Pk5s+f73bs2OG++eYb55xzJSUlbsyYMaH9z368dNq0aW7v3r1u0aJFjX7MuC2dC6OxBm3pXOhcdNbgXC05H3aoQHHOuYULF7pevXq5pKQkd91117nNmzeHnrvpppvc2LFjQ//+6KOPXL9+/VxycrLLyMhwY8aMcd99911Yx7Qo0msgqdHH0qVLW2lG4YnG98AvWQ8U56KzBu+9957r37+/S05Odn379nWvvPJKa0yl2SK9BsFg0E2aNMn16tXLpaSkuCuuuMI99thjrra2trWm1GQffvhho//Nnp3z2LFj3U033XTeawYOHOiSkpLcFVdc0eh/323pXBiNNWhr58JofR/8UkvOh3HOGbzNIQAA6NA6zHtQAABA20GgAAAAcwgUAABgDoECAADMIVAAAIA5BAoAADCHQAEAAOYQKAAAwBwCBQAAmEOgAAAAcwgUAABgDoECAADM+V9LRPsBpVGorwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# plot OH bondlength distribution of the MLMD simulation\n", "traj = Trajectory('example.traj')\n", @@ -202,7 +221,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -229,7 +248,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -262,9 +281,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[32mSuccess!\u001b[0m\n", + "md_config.yaml is a valid MD config.\n" + ] + } + ], "source": [ "!apax validate md md_config.yaml" ] @@ -280,9 +308,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO | 21:44:19 | reading structure\n", + "INFO | 21:44:19 | Unable to initialize backend 'rocm': NOT_FOUND: Could not find registered platform with name: \"rocm\". Available platform names are: CUDA\n", + "INFO | 21:44:19 | Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory\n", + "INFO | 21:44:20 | initializing model\n", + "INFO | 21:44:20 | loading checkpoint from /home/linux3_i1/segreto/uni/dev/apax/examples/project/models/etoh_md/best\n", + "INFO | 21:44:20 | Initializing new trajectory file at md/md.h5\n", + "INFO | 21:44:20 | initializing simulation\n", + "INFO | 21:44:23 | running simulation for 5.0 ps\n", + "Simulation: 0%| | 0/10000 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import znh5md\n", "\n", @@ -318,15 +375,7 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "rm: cannot remove 'project/models/etoh_md/.nfs00000000c5aa84b000000020': Device or resource busy\n" - ] - } - ], + "outputs": [], "source": [ "!rm -rf project md config.yaml example.traj md_config.yaml" ] From 4edf8c613635bca62d017bd3f888973fc066e8a8 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 12:11:59 +0200 Subject: [PATCH 175/192] doc strings update --- apax/config/train_config.py | 2 ++ apax/data/initialization.py | 14 +++++++++++++ apax/data/input_pipeline.py | 32 +++++++++++++++++++++++++++++ apax/data/preprocessing.py | 31 +++++++++++++++++++++++++++- apax/md/ase_calc.py | 4 ++-- apax/md/function_transformations.py | 19 +++++++++++------ apax/md/nvt.py | 29 ++++++++++++-------------- apax/nodes/md.py | 4 ++-- apax/nodes/model.py | 4 ++-- apax/utils/data.py | 24 ++++++++++------------ 10 files changed, 121 insertions(+), 42 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 4643b6ec..f9b901cd 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -325,6 +325,8 @@ class Config(BaseModel, frozen=True, extra="forbid"): Main configuration of a apax training run. Parameter that are cofig classes will be generated by parsing the config.yaml file and are specified as shown :ref:`here `: + Example + ------- .. code-block:: yaml data: diff --git a/apax/data/initialization.py b/apax/data/initialization.py index d81d73e2..f8b5c8c5 100644 --- a/apax/data/initialization.py +++ b/apax/data/initialization.py @@ -8,6 +8,20 @@ def load_data_files(data_config): + """ + Load data files for training and validation. + + Parameters + ---------- + data_config : object + Data configuration object. + + Returns + ------- + Tuple + Tuple containing list of ase.Atoms objects for training and validation. + """ + log.info("Running Input Pipeline") if data_config.data_path is not None: log.info(f"Read data file {data_config.data_path}") diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index fea6c051..a6aceffc 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -17,6 +17,23 @@ def pad_nl(idx, offsets, max_neighbors): + """ + Pad the neighbor list arrays to the maximal number of neighbors occuring. + + Parameters + ---------- + idx : np.ndarray + Neighbor indices array. + offsets : np.ndarray + Offset array. + max_neighbors : int + Maximum number of neighbors. + + Returns + ------- + Tuple[np.ndarray, np.ndarray] + Tuple containing padded neighbor indices array and offsets array. + """ zeros_to_add = max_neighbors - idx.shape[1] idx = np.pad(idx, ((0, 0), (0, zeros_to_add)), "constant").astype(np.int16) offsets = np.pad(offsets, ((0, zeros_to_add), (0, 0)), "constant") @@ -24,6 +41,21 @@ def pad_nl(idx, offsets, max_neighbors): def find_largest_system(inputs, r_max) -> tuple[int]: + """ + Finds the maximal number of atoms and neighbors. + + Parameters + ---------- + inputs : dict + Dictionary containing input data. + r_max : float + Maximum interaction radius. + + Returns + ------- + Tuple[int] + Tuple containing the maximum number of atoms and neighbors. + """ positions, boxes = inputs["positions"], inputs["box"] max_atoms = np.max(inputs["n_atoms"]) diff --git a/apax/data/preprocessing.py b/apax/data/preprocessing.py index 5132aa20..13b7302b 100644 --- a/apax/data/preprocessing.py +++ b/apax/data/preprocessing.py @@ -11,9 +11,25 @@ def compute_nl(positions, box, r_max): - """Computes the NL for a single structure. + """ + Computes the neighbor list for a single structure. For periodic systems, positions are assumed to be in fractional coordinates. + + Parameters + ---------- + positions : np.ndarray + Positions of atoms. + box : np.ndarray + Simulation box dimensions. + r_max : float + Maximum interaction radius. + + Returns + ------- + Tuple[np.ndarray, np.ndarray] + Tuple containing neighbor indices array and offsets array. + """ if np.all(box < 1e-6): box, box_origin = get_shrink_wrapped_cell(positions) @@ -42,6 +58,19 @@ def compute_nl(positions, box, r_max): def get_shrink_wrapped_cell(positions): + """ + Get the shrink-wrapped simulation cell based on atomic positions. + + Parameters + ---------- + positions : np.ndarray + Atomic positions. + + Returns + ------- + Tuple[np.ndarray, np.ndarray] + Tuple containing the shrink-wrapped cell matrix and origin. + """ rmin = np.min(positions, axis=0) rmax = np.max(positions, axis=0) cell_origin = rmin diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index e334afd8..9637940f 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -261,8 +261,8 @@ def batch_eval( 2. Inputs are padded so no recompilation is triggered when evaluating differently sized systems. - Arguments - --------- + Parameters + ---------- atoms_list : List of Atoms to be evaluated. batch_size: diff --git a/apax/md/function_transformations.py b/apax/md/function_transformations.py index 112d0d86..cd75bd54 100644 --- a/apax/md/function_transformations.py +++ b/apax/md/function_transformations.py @@ -35,9 +35,13 @@ class UncertaintyDrivenDynamics(FunctionTransformation): up to some maximum bias energy. https://doi.org/10.1038/s43588-023-00406-5 - Parameters: - height: Maximum bias potential that can be applied - width: Width of the Gaussian bias. + + Parameters + ---------- + height : float + Maximum bias potential that can be applied + width : float + Width of the Gaussian bias. """ @@ -66,9 +70,12 @@ class GaussianAcceleratedMolecularDynamics(FunctionTransformation): Applies a boost potential to the system that pulls it towards a target energy. https://pubs.acs.org/doi/10.1021/acs.jctc.5b00436 - Parameters: - energy_target: Target potential energy below which to apply the boost potential. - spring_constant: Spring constant of the boost potential. + Parameters + ---------- + energy_target : float + Target potential energy below which to apply the boost potential. + spring_constant : float + Spring constant of the boost potential. """ energy_target: float diff --git a/apax/md/nvt.py b/apax/md/nvt.py index 87014987..741574e2 100644 --- a/apax/md/nvt.py +++ b/apax/md/nvt.py @@ -145,25 +145,22 @@ def run_nvt( Parameters ---------- - ensemble: + ensemble : Thermodynamic ensemble. - temperature: - Temperature of the system in K. - n_steps: + n_steps : int Total time steps. - n_inner: + n_inner : int JIT compiled inner loop. Also determines atoms buffer size. - sampling_rate: - Trajectory dumping interval. - extra_capacity: + extra_capacity : int Extra capacity for the neighborlist. - rng_key: + rng_key : int RNG key used to initialize the simulation. - restart: + restart : bool, default = True Whether a checkpoint should be loaded. No implemented yet. - checkpoint_interval: Number of time steps between saving + checkpoint_interval : int, default = 50_000 + Number of time steps between saving full simulation state checkpoints. - sim_dir: + sim_dir : Path Directory where the trajectory and simulation checkpoints will be saved. """ energy_fn = sim_fns.energy_fn @@ -310,9 +307,9 @@ def md_setup(model_config: Config, md_config: MDConfig): Parameters ---------- - model_config: + model_config : Config Configuration of the model used as an interatomic potential. - md_config: + md_config : MDConfig configuration of the MD simulation. Returns @@ -391,9 +388,9 @@ def run_md(model_config: Config, md_config: MDConfig, log_level="error"): Parameters ---------- - model_config: + model_config : Config Configuration of the model used as an interatomic potential. - md_config: + md_config : MDConfig configuration of the MD simulation. """ diff --git a/apax/nodes/md.py b/apax/nodes/md.py index 075ae612..f0a9acaf 100644 --- a/apax/nodes/md.py +++ b/apax/nodes/md.py @@ -20,11 +20,11 @@ class ApaxJaxMD(zntrack.Node): """Class to run a more performant JaxMD simulation with a apax Model. - Attributes + Parameters ---------- data: list[ase.Atoms] MD starting structure - data_id: int, default=-1 + data_id: int, default = -1 index of the configuration from the data list to use model: ApaxModel model to use for the simulation diff --git a/apax/nodes/model.py b/apax/nodes/model.py index e61ad97a..9c74de69 100644 --- a/apax/nodes/model.py +++ b/apax/nodes/model.py @@ -19,7 +19,7 @@ class Apax(zntrack.Node): """Class for the implementation of the apax model - Attributes + Parameters ---------- config: str path to the apax config file @@ -104,7 +104,7 @@ def get_calculator(self, **kwargs): class ApaxEnsemble(zntrack.Node): """Parallel apax model ensemble in ASE. - Attributes + Parameters ---------- models: list List of `ApaxModel` nodes to ensemble. diff --git a/apax/utils/data.py b/apax/utils/data.py index 057f0718..ceecce9d 100644 --- a/apax/utils/data.py +++ b/apax/utils/data.py @@ -89,24 +89,22 @@ def split_idxs(atoms_list, n_train, n_valid): def split_atoms(atoms_list, train_idxs, val_idxs=None): - """Shuffles and splits a list in two resulting lists - of the length length1 and length2. + """ + Split the list of atoms into training and validation sets (validation is optional). Parameters ---------- - data_list : - A list. - length1 : - Length of the first resulting list. - length2 : - Length of the second resulting list. + atoms_list : list[ase.Atoms] + List of atoms. + train_idxs : list[int] + List of indices for the training set. + val_idxs : list[int], optional + List of indices for the validation set. Returns ------- - splitted_list1 - List of random structures from atoms_list of the length length1. - splitted_list2 - List of random structures from atoms_list of the length length2. + Tuple[list, list] + Tuple containing lists of atoms for training and validation sets. """ train_atoms_list = [atoms_list[i] for i in train_idxs] @@ -115,4 +113,4 @@ def split_atoms(atoms_list, train_idxs, val_idxs=None): else: val_atoms_list = [] - return train_atoms_list, val_atoms_list + return train_atoms_list, val_atoms_list \ No newline at end of file From 230b012900e6f46fb0511e87679300b6e49e0976 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 12:12:25 +0200 Subject: [PATCH 176/192] poetry lock update --- poetry.lock | 254 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 227 insertions(+), 27 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1982518e..524242f1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "absl-py" @@ -225,6 +225,17 @@ files = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + [[package]] name = "array-record" version = "0.5.1" @@ -352,7 +363,7 @@ files = [ name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -optional = true +optional = false python-versions = ">=3.7" files = [ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, @@ -568,7 +579,7 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." -optional = true +optional = false python-versions = ">=3.8" files = [ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, @@ -1141,6 +1152,59 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "debugpy" +version = "1.8.1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, + {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, + {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, + {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, + {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, + {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, + {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, + {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, + {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, + {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, + {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, + {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, + {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, + {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, + {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, + {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, + {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, + {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, + {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, + {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, + {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, + {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "dictdiffer" version = "0.9.0" @@ -1614,9 +1678,11 @@ files = [ ] [package.dependencies] +absl-py = {version = "*", optional = true, markers = "extra == \"etqdm\""} fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} numpy = {version = "*", optional = true, markers = "extra == \"enp\""} +tqdm = {version = "*", optional = true, markers = "extra == \"etqdm\""} typing_extensions = {version = "*", optional = true, markers = "extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} @@ -1790,8 +1856,8 @@ files = [ jax = ">=0.4.19" msgpack = "*" numpy = [ - {version = ">=1.22", markers = "python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.22", markers = "python_version < \"3.11\""}, ] optax = "*" orbax-checkpoint = "*" @@ -2662,8 +2728,8 @@ files = [ [package.dependencies] ml-dtypes = ">=0.2.0" numpy = [ - {version = ">=1.22", markers = "python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.22", markers = "python_version < \"3.11\""}, ] opt-einsum = "*" scipy = ">=1.9" @@ -3391,8 +3457,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.21.2", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.2", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] [package.extras] @@ -3515,6 +3581,105 @@ files = [ {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] +[[package]] +name = "multidict" +version = "6.0.5" +description = "multidict implementation" +optional = true +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -3965,8 +4130,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -4246,7 +4411,7 @@ test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", name = "prompt-toolkit" version = "3.0.43" description = "Library for building powerful interactive command lines in Python" -optional = true +optional = false python-versions = ">=3.7.0" files = [ {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, @@ -4772,7 +4937,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -4780,15 +4944,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -4805,7 +4962,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -4813,7 +4969,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -5159,24 +5314,24 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, @@ -5184,7 +5339,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, @@ -5192,7 +5347,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, @@ -5200,7 +5355,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, @@ -5726,6 +5881,26 @@ dev = ["build", "flake8"] doc = ["sphinx"] test = ["pytest", "pytest-cov"] +[[package]] +name = "sqltrie" +version = "0.11.0" +description = "SQL-based prefix tree inspired by pygtrie and python-diskcache" +optional = true +python-versions = ">=3.8" +files = [ + {file = "sqltrie-0.11.0-py3-none-any.whl", hash = "sha256:132c3d2675dd14970093e2f8dcde906f7a3c900c4477641da71c0c8627eb5a0e"}, + {file = "sqltrie-0.11.0.tar.gz", hash = "sha256:e613a74843e2b55ce1d20d333100d6a41127a1d6c12f835915f58fbd13944a82"}, +] + +[package.dependencies] +attrs = "*" +orjson = {version = "*", markers = "implementation_name == \"cpython\""} +pygtrie = "*" + +[package.extras] +dev = ["sqltrie[tests]"] +tests = ["mypy (==0.971)", "pyinstaller", "pytest (==7.2.0)", "pytest-benchmark", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.5)"] + [[package]] name = "stack-data" version = "0.6.3" @@ -5745,6 +5920,20 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = true +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + [[package]] name = "tensorboard" version = "2.15.2" @@ -6359,6 +6548,17 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "voluptuous" +version = "0.14.2" +description = "Python data validation library" +optional = true +python-versions = ">=3.8" +files = [ + {file = "voluptuous-0.14.2-py3-none-any.whl", hash = "sha256:efc1dadc9ae32a30cc622602c1400a17b7bf8ee2770d64f70418144860739c3b"}, + {file = "voluptuous-0.14.2.tar.gz", hash = "sha256:533e36175967a310f1b73170d091232bf881403e4ebe52a9b4ade8404d151f5d"}, +] + [[package]] name = "waitress" version = "3.0.0" @@ -6381,8 +6581,8 @@ description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "voluptuous-0.14.2-py3-none-any.whl", hash = "sha256:efc1dadc9ae32a30cc622602c1400a17b7bf8ee2770d64f70418144860739c3b"}, - {file = "voluptuous-0.14.2.tar.gz", hash = "sha256:533e36175967a310f1b73170d091232bf881403e4ebe52a9b4ade8404d151f5d"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -6728,4 +6928,4 @@ zntrack = ["zntrack"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "e653af1e109d3da222e17f50a2519e9775c7392e5114dab48bffbb83bf5c58df" +content-hash = "c5e343f1c07c5e97a02d1024649acfd605bc95bcf01ac53a8ac03ab5718f25f0" From 38ee48503e401202171c2db485c3182aa6f2492c Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 12:26:48 +0200 Subject: [PATCH 177/192] more doc strings --- apax/config/common.py | 9 ++++--- apax/config/md_config.py | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index cae30bda..06ed2e90 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -14,10 +14,13 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> Config: """Load the training configuration from file or a dictionary. - Attributes + Parameters ---------- - config: Path to the config file or a dictionary - containing the config. + config : str | os.PathLike | dict + Path to the config file or a dictionary + containing the config. + mode: str, default = train + Defines if the config is validated for training ("train") or MD simulation("md"). """ if isinstance(config, (str, os.PathLike)): with open(config, "r") as stream: diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 08a98d2d..0cc47671 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -8,6 +8,20 @@ class NHCOptions(BaseModel, extra="forbid"): + """ + Options for Nose-Hoover chain thermostat. + + Attributes + ---------- + chain_length : PositiveInt, default = 3 + Number of thermostats in the chain. + chain_steps : PositiveInt, default = 2 + Number of steps per chain. + sy_steps : PositiveInt, default = 3 + Number of steps for Suzuki-Yoshida integration. + tau : PositiveFloat, default = 100 + Relaxation time parameter. + """ chain_length: PositiveInt = 3 chain_steps: PositiveInt = 2 sy_steps: PositiveInt = 3 @@ -15,20 +29,60 @@ class NHCOptions(BaseModel, extra="forbid"): class Integrator(BaseModel, extra="forbid"): + """ + Molecular dynamics integrator options. + + Attributes + ---------- + dt : PositiveFloat, default = 0.5 + Time step size in femtoseconds (fs). + """ dt: PositiveFloat = 0.5 # fs class NVEOptions(Integrator, extra="forbid"): + """ + Options for NVE ensemble simulations. + + Attributes + ---------- + name : Literal["nve"] + Name of the ensemble. + """ name: Literal["nve"] class NVTOptions(Integrator, extra="forbid"): + """ + Options for NVT ensemble simulations. + + Attributes + ---------- + name : Literal["nvt"] + Name of the ensemble. + temperature : PositiveFloat, default = 298.15 + Temperature in Kelvin (K). + thermostat_chain : NHCOptions, default = NHCOptions() + Thermostat chain options. + """ name: Literal["nvt"] temperature: PositiveFloat = 298.15 # K thermostat_chain: NHCOptions = NHCOptions() class NPTOptions(NVTOptions, extra="forbid"): + """ + Options for NPT ensemble simulations. + + Attributes + ---------- + name : Literal["npt"] + Name of the ensemble. + pressure : PositiveFloat, default = 1.01325 + Pressure in bar. + barostat_chain : NHCOptions, default = NHCOptions(tau=1000) + Barostat chain options. + """ name: Literal["npt"] pressure: PositiveFloat = 1.01325 # bar barostat_chain: NHCOptions = NHCOptions(tau=1000) From 1fe6f2db9a4aa30c78d7d47f65d548ab8f0f9598 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 12:31:31 +0200 Subject: [PATCH 178/192] descriptor_dtype default = fp64 --- apax/config/train_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index f9b901cd..9a6022e0 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -168,7 +168,7 @@ class ModelConfig(BaseModel, extra="forbid"): calc_stress: bool = False - descriptor_dtype: Literal["fp32", "fp64"] = "fp32" + descriptor_dtype: Literal["fp32", "fp64"] = "fp64" readout_dtype: Literal["fp32", "fp64"] = "fp32" scale_shift_dtype: Literal["fp32", "fp64"] = "fp32" From 2fc94f4567c075a11c513cce43d2ad90c8f9e926 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 12:42:39 +0200 Subject: [PATCH 179/192] more doc strings --- apax/config/train_config.py | 92 +++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 9a6022e0..34937cf7 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -139,18 +139,30 @@ class ModelConfig(BaseModel, extra="forbid"): Parameters ---------- - n_basis : - | Number of uncontracted gaussian basis functions. - n_radial : - | Number of contracted basis functions. - r_min : - | Position of the first uncontracted basis function's mean. - r_max : - | Cutoff radius of the descriptor. - nn : - | Number of hidden layers and units in those layers. - b_init : - | Initialization scheme for the neural network biases. Either `normal` or `zeros`. + n_basis : PositiveInt, default = 7 + Number of uncontracted gaussian basis functions. + n_radial : PositiveInt, default = 5 + Number of contracted basis functions. + r_min : NonNegativeFloat, default = 0.5 + Position of the first uncontracted basis function's mean. + r_max : PositiveFloat, default = 6.0 + Cutoff radius of the descriptor. + nn : List[PositiveInt], default = [512, 512] + Number of hidden layers and units in those layers. + b_init : Literal["normal", "zeros"], default = "normal" + Initialization scheme for the neural network biases. + emb_init : Optional[str], default = "uniform" + Initialization scheme for embedding layer weights. + use_zbl : bool, default = False + Whether to include the ZBL correction. + calc_stress : bool, default = False + Whether to calculate stress during model evaluation. + descriptor_dtype : Literal["fp32", "fp64"], default = "fp64" + Data type for descriptor calculations. + readout_dtype : Literal["fp32", "fp64"], default = "fp32" + Data type for readout calculations. + scale_shift_dtype : Literal["fp32", "fp64"], default = "fp32" + Data type for scale and shift parameters. """ n_basis: PositiveInt = 7 @@ -188,17 +200,27 @@ class OptimizerConfig(BaseModel, frozen=True, extra="forbid"): """ Configuration of the optimizer. Learning rates of 0 will freeze the respective parameters. - + Parameters ---------- - opt_name: Name of the optimizer. Can be any `optax` optimizer. - emb_lr: Learning rate of the elemental embedding contraction coefficients. - nn_lr: Learning rate of the neural network parameters. - scale_lr: Learning rate of the elemental output scaling factors. - shift_lr: Learning rate of the elemental output shifts. - transition_begin: Number of training steps (not epochs) before the start of the - linear learning rate schedule. - opt_kwargs: Optimizer keyword arguments. Passed to the `optax` optimizer. + opt_name : str, default = "adam" + Name of the optimizer. Can be any `optax` optimizer. + emb_lr : NonNegativeFloat, default = 0.02 + Learning rate of the elemental embedding contraction coefficients. + nn_lr : NonNegativeFloat, default = 0.03 + Learning rate of the neural network parameters. + scale_lr : NonNegativeFloat, default = 0.001 + Learning rate of the elemental output scaling factors. + shift_lr : NonNegativeFloat, default = 0.05 + Learning rate of the elemental output shifts. + zbl_lr : NonNegativeFloat, default = 0.001 + Learning rate of the ZBL correction parameters. + transition_begin : int, default = 0 + Number of training steps (not epochs) before the start of the linear learning rate schedule. + opt_kwargs : dict, default = {} + Optimizer keyword arguments. Passed to the `optax` optimizer. + sam_rho : NonNegativeFloat, default = 0.0 + Rho parameter for Sharpness-Aware Minimization. """ opt_name: str = "adam" @@ -218,10 +240,11 @@ class MetricsConfig(BaseModel, extra="forbid"): Parameters ---------- - name: Keyword of the quantity e.g `energy`. - reductions: List of reductions performed on the difference between - target and predictions. Can be mae, mse, rmse for energies and forces. - For forces it is also possible to use `angle`. + name : str + Keyword of the quantity, e.g., 'energy'. + reductions : List[str] + List of reductions performed on the difference between target and predictions. + Can be 'mae', 'mse', 'rmse' for energies and forces. For forces, 'angle' can also be used. """ name: str @@ -234,10 +257,21 @@ class LossConfig(BaseModel, extra="forbid"): Parameters ---------- - name: Keyword of the quantity e.g `energy`. - loss_type: Weighting scheme for atomic contributions. See the MLIP package - for reference 10.1088/2632-2153/abc9fe for details - weight: Weighting factor in the overall loss function. + name : str + Keyword of the quantity, e.g., 'energy'. + loss_type : str, optional + Weighting scheme for atomic contributions. See the MLIP package + for reference 10.1088/2632-2153/abc9fe for details, by default "mse". + weight : NonNegativeFloat, optional + Weighting factor in the overall loss function, by default 1.0. + atoms_exponent : NonNegativeFloat, optional + Exponent for atomic contributions weighting, by default 1. + parameters : dict, optional + Additional parameters for configuring the loss function, by default {}. + + Notes + ----- + This class specifies the configuration of the loss functions used during training. """ name: str From e2e9422e11538a5cbd780f1d854a014f37e61e88 Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 14:11:59 +0200 Subject: [PATCH 180/192] docs correction --- apax/config/md_config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 0cc47671..d2f75fae 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -11,7 +11,7 @@ class NHCOptions(BaseModel, extra="forbid"): """ Options for Nose-Hoover chain thermostat. - Attributes + Parameters ---------- chain_length : PositiveInt, default = 3 Number of thermostats in the chain. @@ -32,7 +32,7 @@ class Integrator(BaseModel, extra="forbid"): """ Molecular dynamics integrator options. - Attributes + Parameters ---------- dt : PositiveFloat, default = 0.5 Time step size in femtoseconds (fs). @@ -56,7 +56,7 @@ class NVTOptions(Integrator, extra="forbid"): """ Options for NVT ensemble simulations. - Attributes + Parameters ---------- name : Literal["nvt"] Name of the ensemble. @@ -74,7 +74,7 @@ class NPTOptions(NVTOptions, extra="forbid"): """ Options for NPT ensemble simulations. - Attributes + Parameters ---------- name : Literal["npt"] Name of the ensemble. From 4e6ff5164697e353e51df0d1c097947dc988badb Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 15:28:18 +0200 Subject: [PATCH 181/192] cleanup docs page --- apax/config/md_config.py | 2 +- apax/config/train_config.py | 2 +- docs/source/configs/full_configs.rst | 21 +++++++++++++++++++++ docs/source/configs/index.rst | 7 +++++++ docs/source/getting_started/full_config.rst | 11 ----------- docs/source/index.rst | 2 ++ 6 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 docs/source/configs/full_configs.rst create mode 100644 docs/source/configs/index.rst delete mode 100644 docs/source/getting_started/full_config.rst diff --git a/apax/config/md_config.py b/apax/config/md_config.py index d2f75fae..b230c9e0 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -90,7 +90,7 @@ class NPTOptions(NVTOptions, extra="forbid"): class MDConfig(BaseModel, frozen=True, extra="forbid"): """ - Configuration for a NHC molecular dynamics simulation. + Configuration for a NHC molecular dynamics simulation. Full config :ref:`here `: Parameters ---------- diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 34937cf7..9acacf86 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -357,7 +357,7 @@ class CheckpointConfig(BaseModel, extra="forbid"): class Config(BaseModel, frozen=True, extra="forbid"): """ Main configuration of a apax training run. Parameter that are cofig classes will - be generated by parsing the config.yaml file and are specified as shown :ref:`here `: + be generated by parsing the config.yaml file and are specified as shown :ref:`here `: Example ------- diff --git a/docs/source/configs/full_configs.rst b/docs/source/configs/full_configs.rst new file mode 100644 index 00000000..cb46fff4 --- /dev/null +++ b/docs/source/configs/full_configs.rst @@ -0,0 +1,21 @@ + +.. _train_config: +====== +Training Config +====== + +Full config can be downloaded :download:`here <../../../apax/cli/templates/train_config_full.yaml>`. + +.. include:: ../../../apax/cli/templates/train_config_full.yaml + :literal: + +.. _md_config: +====== +Molecular Dynamics Config +====== + +Full config can be downloaded :download:`here <../../../apax/cli/templates/md_config_minimal.yaml>`. + +.. include:: ../../../apax/cli/templates/md_config_minimal.yaml + :literal: + diff --git a/docs/source/configs/index.rst b/docs/source/configs/index.rst new file mode 100644 index 00000000..ed0ef4ec --- /dev/null +++ b/docs/source/configs/index.rst @@ -0,0 +1,7 @@ +Input Parameter +======= + +.. toctree:: + :maxdepth: 2 + + full_configs \ No newline at end of file diff --git a/docs/source/getting_started/full_config.rst b/docs/source/getting_started/full_config.rst deleted file mode 100644 index 3b0cade1..00000000 --- a/docs/source/getting_started/full_config.rst +++ /dev/null @@ -1,11 +0,0 @@ - -.. _config: -====== -Config -====== - -Full config can be downloaded :download:`here <../../../apax/cli/templates/train_config_full.yaml>`. - -.. include:: ../../../apax/cli/templates/train_config_full.yaml - :literal: - diff --git a/docs/source/index.rst b/docs/source/index.rst index d58cd9ba..3601e518 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -11,4 +11,6 @@ It is based on `JAX `_ and uses `JaxMD Date: Wed, 10 Apr 2024 16:43:33 +0200 Subject: [PATCH 182/192] docs linting --- apax/cli/templates/md_config_minimal.yaml | 16 +- apax/cli/templates/train_config_full.yaml | 29 +- apax/config/md_config.py | 20 +- apax/config/train_config.py | 15 +- apax/md/function_transformations.py | 2 +- apax/train/run.py | 9 +- apax/train/trainer.py | 4 +- apax/utils/data.py | 2 +- apax/utils/jax_md_reduced/partition.py | 2 +- docs/source/configs/full_configs.rst | 11 +- docs/source/configs/index.rst | 2 +- docs/source/getting_started/index.rst | 3 +- examples/01_Model_Training.ipynb | 7 +- examples/02_Molecular_Dynamics.ipynb | 5 +- examples/05_Full_Config.ipynb | 439 ---------------------- 15 files changed, 76 insertions(+), 490 deletions(-) delete mode 100644 examples/05_Full_Config.ipynb diff --git a/apax/cli/templates/md_config_minimal.yaml b/apax/cli/templates/md_config_minimal.yaml index 597c24f9..d59829fc 100644 --- a/apax/cli/templates/md_config_minimal.yaml +++ b/apax/cli/templates/md_config_minimal.yaml @@ -2,11 +2,23 @@ ensemble: name: nvt dt: 0.5 # fs time step temperature: # K + thermostat_chain: + chain_length: 3 + chain_steps: 2 + sy_steps: 3 + tau: 100 duration: # fs -n_inner: 1 # compiled innner steps -sampling_rate: 1 # dump interval +n_inner: 100 # compiled innner steps +sampling_rate: 10 # dump interval +buffer_size: 100 dr_threshold: 0.5 # Neighborlist skin +extra_capacity: 0 sim_dir: md initial_structure: +load_momenta: false +traj_name: md.h5 +restart: true +checkpoint_interval: 50_000 +disable_pbar: false \ No newline at end of file diff --git a/apax/cli/templates/train_config_full.yaml b/apax/cli/templates/train_config_full.yaml index 3a7d9d75..4b5f7edf 100644 --- a/apax/cli/templates/train_config_full.yaml +++ b/apax/cli/templates/train_config_full.yaml @@ -1,5 +1,9 @@ n_epochs: seed: 1 +patience: null +n_models: 1 +n_jitted_steps: 1 +data_parallel: True data: directory: models/ @@ -11,6 +15,8 @@ data: #train_data_path: #val_data_path: #test_data_path: + additional_properties_info: {} + ds_type: cached n_train: 1000 n_valid: 100 @@ -20,6 +26,10 @@ data: shift_method: "per_element_regression_shift" shift_options: {"energy_regularisation": 1.0} + + scale_method: "per_element_force_rms_scale" + scale_options: {} + shuffle_buffer_size: 1000 pos_unit: Ang @@ -28,25 +38,30 @@ data: model: n_basis: 7 n_radial: 5 + n_contr: -1 nn: [512, 512] r_max: 6.0 r_min: 0.5 + calc_stress: true use_zbl: false b_init: normal - descriptor_dtype: fp32 + descriptor_dtype: fp64 readout_dtype: fp32 scale_shift_dtype: fp32 + emb_init: uniform loss: -- loss_type: structures - name: energy +- name: energy + loss_type: mse weight: 1.0 -- loss_type: structures - name: forces + atoms_exponent: 1 +- name: forces + loss_type: mse weight: 4.0 + atoms_exponent: 1 metrics: - name: energy @@ -66,7 +81,8 @@ optimizer: shift_lr: 0.05 zbl_lr: 0.001 transition_begin: 0 - + sam_rho: 0.0 + callbacks: - name: csv @@ -78,3 +94,4 @@ checkpoints: progress_bar: disable_epoch_pbar: false + disable_batch_pbar: true \ No newline at end of file diff --git a/apax/config/md_config.py b/apax/config/md_config.py index b230c9e0..3d7ed223 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -22,6 +22,7 @@ class NHCOptions(BaseModel, extra="forbid"): tau : PositiveFloat, default = 100 Relaxation time parameter. """ + chain_length: PositiveInt = 3 chain_steps: PositiveInt = 2 sy_steps: PositiveInt = 3 @@ -37,6 +38,7 @@ class Integrator(BaseModel, extra="forbid"): dt : PositiveFloat, default = 0.5 Time step size in femtoseconds (fs). """ + dt: PositiveFloat = 0.5 # fs @@ -49,6 +51,7 @@ class NVEOptions(Integrator, extra="forbid"): name : Literal["nve"] Name of the ensemble. """ + name: Literal["nve"] @@ -65,6 +68,7 @@ class NVTOptions(Integrator, extra="forbid"): thermostat_chain : NHCOptions, default = NHCOptions() Thermostat chain options. """ + name: Literal["nvt"] temperature: PositiveFloat = 298.15 # K thermostat_chain: NHCOptions = NHCOptions() @@ -83,6 +87,7 @@ class NPTOptions(NVTOptions, extra="forbid"): barostat_chain : NHCOptions, default = NHCOptions(tau=1000) Barostat chain options. """ + name: Literal["npt"] pressure: PositiveFloat = 1.01325 # bar barostat_chain: NHCOptions = NHCOptions(tau=1000) @@ -103,8 +108,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): duration : float, required | Total simulation time in fs. n_inner : int, default = 100 - | Number of compiled simulation steps (i.e. number of iterations of the - `jax.lax.fori_loop` loop). Also determines atoms buffer size. + | Number of compiled simulation steps (i.e. number of iterations of the `jax.lax.fori_loop` loop). Also determines atoms buffer size. sampling_rate : int, default = 10 | Interval between saving frames. buffer_size : int, default = 100 @@ -112,9 +116,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): dr_threshold : float, default = 0.5 | Skin of the neighborlist. extra_capacity : int, default = 0 - | JaxMD allocates a maximal number of neighbors. - This argument lets you add additional capacity to avoid recompilation. - The default is usually fine. + | JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. initial_structure : str, required | Path to the starting structure of the simulation. sim_dir : str, default = "." @@ -122,12 +124,9 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): traj_name : str, default = "md.h5" | Name of the trajectory file. restart : bool, default = True - | Whether the simulation should restart from the latest configuration - in `traj_name`. + | Whether the simulation should restart from the latest configuration in `traj_name`. checkpoint_interval : int, default = 50_000 - | Number of time steps between saving - full simulation state checkpoints. These will be loaded - with the `restart` option. + | Number of time steps between saving full simulation state checkpoints. These will be loaded with the `restart` option. disable_pbar : bool, False | Disables the MD progressbar. """ @@ -157,6 +156,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): def dump_config(self): """ Writes the current config file to the MD directory. + """ with open(os.path.join(self.sim_dir, "md_config.yaml"), "w") as conf: yaml.dump(self.model_dump(), conf, default_flow_style=False) diff --git a/apax/config/train_config.py b/apax/config/train_config.py index 9acacf86..d771bf18 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -30,8 +30,8 @@ class DataConfig(BaseModel, extra="forbid"): directory : str, required | Path to directory where training results and checkpoints are written. experiment : str, required - | Model name distinguishing from others in directory. - data_path : str, required if train_ and val_data_path is not specified + | Model name distinguishing from others in directory. + data_path : str, required if train_data_path and val_data_path is not specified | Path to single dataset file. train_data_path : str, required if data_path is not specified | Path to training dataset. @@ -51,8 +51,9 @@ class DataConfig(BaseModel, extra="forbid"): | Size of the `tf.data` shuffle buffer. additional_properties_info : dict, optional | dict of property name, shape (ragged or fixed) pairs - energy_regularisation : + energy_regularisation : | Magnitude of the regularization in the per-element energy regression. + """ directory: str @@ -200,7 +201,7 @@ class OptimizerConfig(BaseModel, frozen=True, extra="forbid"): """ Configuration of the optimizer. Learning rates of 0 will freeze the respective parameters. - + Parameters ---------- opt_name : str, default = "adam" @@ -380,8 +381,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): n_models : int, default = 1 | Number of models to be trained at once. n_jitted_steps : int, default = 1 - | Number of train batches to be processed in a compiled loop. - Can yield singificant speedups for small structures or small batch sizes. + | Number of train batches to be processed in a compiled loop. Can yield singificant speedups for small structures or small batch sizes. data : :class:`.DataConfig` | Data configuration. model : :class:`.ModelConfig` @@ -399,8 +399,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): checkpoints : :class:`.CheckpointConfig` | Checkpoint configuration. data_parallel : bool, default = True - | Automatically uses all available GPUs for data parallel training. - Set to false to force single device training. + | Automatically uses all available GPUs for data parallel training. Set to false to force single device training. """ n_epochs: PositiveInt diff --git a/apax/md/function_transformations.py b/apax/md/function_transformations.py index cd75bd54..1ad9a112 100644 --- a/apax/md/function_transformations.py +++ b/apax/md/function_transformations.py @@ -35,7 +35,7 @@ class UncertaintyDrivenDynamics(FunctionTransformation): up to some maximum bias energy. https://doi.org/10.1038/s43588-023-00406-5 - + Parameters ---------- height : float diff --git a/apax/train/run.py b/apax/train/run.py index 0c1203fc..da946c77 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -1,8 +1,7 @@ import logging -import sys -from typing import List -from typing import Union import os +import sys +from typing import List, Union import jax @@ -139,9 +138,9 @@ def run(user_config: Union[str, os.PathLike, dict], log_level="error"): Parameters ---------- - user_config : str | os.PathLike | dict - training config full exmaple can be finde :ref:`here `: + training config full exmaple can be finde :ref:`here `: + """ config = parse_config(user_config) diff --git a/apax/train/trainer.py b/apax/train/trainer.py index dc39346c..f3add601 100644 --- a/apax/train/trainer.py +++ b/apax/train/trainer.py @@ -40,7 +40,7 @@ def fit( Parameters ---------- - state : + state : The initial state of the model. train_ds : InMemoryDataset The training dataset. @@ -48,7 +48,7 @@ def fit( The loss function to be minimized. Metrics metrics.Collection : Collection of metrics to evaluate during training. - callbacks : list + callbacks : list List of callback functions to be executed during training. n_epochs : int Number of epochs for training. diff --git a/apax/utils/data.py b/apax/utils/data.py index ceecce9d..8816164d 100644 --- a/apax/utils/data.py +++ b/apax/utils/data.py @@ -113,4 +113,4 @@ def split_atoms(atoms_list, train_idxs, val_idxs=None): else: val_atoms_list = [] - return train_atoms_list, val_atoms_list \ No newline at end of file + return train_atoms_list, val_atoms_list diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 72259a4c..36a7bafb 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -722,7 +722,7 @@ def neighbor_fn(position_and_error, max_occupancy=None): if not is_sparse(format): capacity_limit = N - 1 if mask_self else N elif format is NeighborListFormat.Sparse: - capacity_limit = N * (N - 1) if mask_self else N**2 + capacity_limit = N * (N - 1) if mask_self else N ** 2 else: capacity_limit = N * (N - 1) // 2 if max_occupancy > capacity_limit: diff --git a/docs/source/configs/full_configs.rst b/docs/source/configs/full_configs.rst index cb46fff4..56042d43 100644 --- a/docs/source/configs/full_configs.rst +++ b/docs/source/configs/full_configs.rst @@ -1,8 +1,8 @@ - .. _train_config: -====== + +=============== Training Config -====== +=============== Full config can be downloaded :download:`here <../../../apax/cli/templates/train_config_full.yaml>`. @@ -10,9 +10,10 @@ Full config can be downloaded :download:`here <../../../apax/cli/templates/train :literal: .. _md_config: -====== + +========================= Molecular Dynamics Config -====== +========================= Full config can be downloaded :download:`here <../../../apax/cli/templates/md_config_minimal.yaml>`. diff --git a/docs/source/configs/index.rst b/docs/source/configs/index.rst index ed0ef4ec..9cdcfeaa 100644 --- a/docs/source/configs/index.rst +++ b/docs/source/configs/index.rst @@ -1,5 +1,5 @@ Input Parameter -======= +=============== .. toctree:: :maxdepth: 2 diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index beb0aa86..5c2c49c0 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -4,5 +4,4 @@ Getting Started .. toctree:: :maxdepth: 2 - install - full_config \ No newline at end of file + install \ No newline at end of file diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index fc656eb2..9f3d012d 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -100,7 +100,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The following command create a minimal configuration file in the working directory. Full configuration file with descriptiond of the prameter can be found [here](./05_Full_Config.ipynb)." + "The following command create a minimal configuration file in the working directory. Full configuration file with descriptiond of the prameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/train_config_full.yaml)." ] }, { @@ -280,7 +280,7 @@ "\n", "\n", "During training, apax displays a progress bar to keep track of the validation loss.\n", - "This progress bar is optional however and can be turned off in the config. LINK\n", + "This progress bar is optional however and can be turned off in the config.\n", "The default configuration writes training metrics to a CSV file, but TensorBoard is also supported.\n", "One can specify which to use by adding the following section to the input file:\n", "\n", @@ -454,9 +454,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "TODO pretty print results to the terminal\n", - "\n", "Congratulations, you have successfully trained and evaluated your first apax model!" ] }, diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index b18ea941..59448fd8 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -208,7 +208,7 @@ "The CLI provides easy access to standard NVT and NPT simulations.\n", "More complex simulation loops are relatively easy to build yourself in JaxMD (see their colab notebooks for examples). \n", "Trained apax models can of course be used as `energy_fn` in such custom simulations.\n", - "If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on [Github]{https://github.com/apax-hub/apax}.\n" + "If you have a suggestion for adding some MD feature or thermostat to the core of `apax`, feel free to open up an issue on [Github](https://github.com/apax-hub/apax).\n" ] }, { @@ -243,7 +243,8 @@ " \n", "duration: 20_000 # fs\n", "initial_structure: project/benzene_mod.xyz\n", - "```\n" + "```\n", + "Full configuration file with descriptiond of the prameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/md_config_minimal.yaml)." ] }, { diff --git a/examples/05_Full_Config.ipynb b/examples/05_Full_Config.ipynb deleted file mode 100644 index 8dc92ed1..00000000 --- a/examples/05_Full_Config.ipynb +++ /dev/null @@ -1,439 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#TODO add all options to description of the parameter example ïsolated_atoms_shift and per_element_regression_shift\n", - "\n", - "- **n_epochs**: int (required)\n", - "\n", - " >Number of training epochs.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **seed**: int (default = 1)\n", - " \n", - " >Seed for initializing random numbers.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **patience**: int (optional)\n", - "\n", - " >Number of epochs without improvement before training termination.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **n_models**: int (default = 1)\n", - "\n", - " >Number of models trained simultaneously.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **n_jitted_steps**: int (default = 1)\n", - "\n", - " >Number of train batches in a compiled loop. Can speed up for small batches." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Data**\n", - " - directory: str (default = \"/models\")\n", - "\n", - " >Path to directory where training results and checkpoints are written.\n", - "\n", - "\n", - " - experiment: str (default = \"apax\")\n", - "\n", - " >Model name distinguishing from others in directory. \n", - "\n", - "\n", - " - data_path: str (required if train_ and val_data_path is not specified)\n", - "\n", - " >Path to single dataset file.\n", - " \n", - "\n", - " - train_data_path: str (required if data_path is not specified)\n", - " >Path to training dataset.\n", - "\n", - " - val_data_path: str (required if data_path is not specified)\n", - " >Path to validation dataset.\n", - "\n", - " - test_data_path: str (optional)\n", - " >Path to test dataset.\n", - "\n", - " - n_train: int (default = 1000)\n", - " >Number of training data points.\n", - " \n", - " - n_valid: int (default = 100)\n", - " >Number of validation data points.\n", - " \n", - " - batch_size: int (default = 32)\n", - " >Number of training examples evaluated at once.\n", - " \n", - " - valid_batch_size: int (default = 100)\n", - " >Number of validation examples evaluated at once.\n", - " \n", - " - shift_method: str (default = \"per_element_regression_shift\")\n", - " >Method for shifting.\n", - " \n", - " - shift_options: dict (default = {\"energy_regularization\": 1.0})\n", - " >Regularization magnitude for energy regression. #TODO fill in the other options\n", - " \n", - " - shuffle_buffer_size: int (default = 1000)\n", - " >Size of `tf.data` shuffle buffer.\n", - " \n", - " - pos_unit: str (default = \"Ang\")\n", - " >Positional unit.\n", - " \n", - " - energy_unit: str (default = \"eV\")\n", - " >Energy unit.\n", - " \n", - " - additional_properties_info: dict (optional)\n", - " >Dictionary of property name, shape pairs.\n", - " \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Model**\n", - " - n_basis: int (default = 7)\n", - " >Number of Gaussian basis functions.\n", - "\n", - " - n_radial: int (default = 5)\n", - " >Number of contracted basis functions.\n", - "\n", - " - nn: list of int (default = [512, 512])\n", - " >Hidden layers and units.\n", - "\n", - " - r_max: float (default = 6.0)\n", - " >Maximum position of first basis function's mean in angstrom.\n", - "\n", - " - r_min: float (default = 0.5)\n", - " >Descriptor cutoff radius in angstrom.\n", - "\n", - " - use_zbl: bool (default = false)\n", - " >Use emperical Ziegler-Biersack-Littmark potential.\n", - "\n", - " - b_init: str (default = \"normal\")\n", - " >Initialization scheme for biases. #TODO fill in the other options\n", - "\n", - " - descriptor_dtype: str (default = \"fp64\")\n", - " >Descriptor data type.\n", - "\n", - " - readout_dtype: str (default = \"fp32\")\n", - " >Readout data type.\n", - "\n", - " - scale_shift_dtype: str (default = \"fp32\")\n", - " >Scale/Shift data type.\n", - " \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Loss**\n", - " - loss_type: str (default = \"structures\")\n", - " >Weighting scheme for atomic contributions. #TODO fill in the other options\n", - "\n", - " - name: str (default = \"energy\")\n", - " >Quantity keyword.\n", - "\n", - " - weight: float (default = 1.0)\n", - " >Weighting factor in loss function.\n", - "\n", - " - name: str (default = \"forces\")\n", - " >Quantity keyword.\n", - "\n", - " - weight: float (default = 4.0)\n", - " >Weighting factor in loss function." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Metrics**\n", - " - name: str (default = \"energy\")\n", - " >Quantity keyword.\n", - " \n", - " - reductions:\n", - " >List of reductions on target-prediction differences.\n", - " \n", - " - name: str (default = \"forces\")\n", - " >Quantity keyword.\n", - " \n", - " - reductions: list of str (default = [mae, mse])\n", - " >Reductions on target-prediction differences.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Optimizer**\n", - " - opt_name: str (default = \"adam\")\n", - " >Optimizer name. #TODO fill in the other options\n", - " \n", - " - opt_kwargs: dict (if optimizer requires)\n", - " >Optimizer keyword arguments.\n", - " \n", - " - emb_lr: float (default = 0.03)\n", - " >Learning rate for elemental embedding contraction coefficients.\n", - " \n", - " - nn_lr: float (default = 0.03)\n", - " >Learning rate for neural network parameters.\n", - " \n", - " - scale_lr: float (default = 0.001)\n", - " >Learning rate for elemental output scaling factors.\n", - " \n", - " - shift_lr: float (default = 0.05)\n", - " >Learning rate for elemental output shifts.\n", - " \n", - " - zbl_lr: float (default = 0.001)\n", - " >Learning rate for Zero-Body-Loss.\n", - " \n", - " - transition_begin: int (default = 0)\n", - " >Training steps before linear learning rate schedule.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Callbacks**\n", - " - name: str (default = \"csv\") \n", - " >Callback name.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- **Progress Bar**\n", - " - disable_epoch_pbar: bool (default = false)\n", - " >Disable epoch progress bar.\n", - "\n", - " - disable_nl_pbar: bool (default = false)\n", - " >Disable NL precomputation progress bar.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- **Checkpoints**\n", - " - ckpt_interval: int (default = 1)\n", - " >Epochs between checkpoints.\n", - " \n", - " - base_model_checkpoint: (optional)\n", - " >Path to pre-trained model checkpoint.\n", - " \n", - " - reset_layers: (optional)\n", - " >List of layers to reinitialize parameters." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Parameter | Default Value | Description |\n", - "|----------------------------|--------------------------------|-----------------------------------------------------------------------------|\n", - "| **n_epochs** | `` | Number of training epochs. |\n", - "| **seed** | 1 | Seed for initializing random numbers. |\n", - "| **patience** | None | Number of epochs without improvement before training termination. |\n", - "| **n_models** | 1 | Number of models trained simultaneously. |\n", - "| **n_jitted_steps** | 1 | Number of train batches in a compiled loop. Can speed up for small batches. |\n", - "| **Data** | | |\n", - "| directory | models/ | Path to directory where training results and checkpoints are written. |\n", - "| experiment | apax | Model name distinguishing from others in directory. |\n", - "| data_path | `` | Path to single dataset file. |\n", - "| train_data_path | `` | Path to training dataset. |\n", - "| val_data_path | `` | Path to validation dataset. |\n", - "| test_data_path | `` | Path to test dataset. |\n", - "| n_train | 1000 | Number of training data points. |\n", - "| n_valid | 100 | Number of validation data points. |\n", - "| batch_size | 32 | Number of training examples evaluated at once. |\n", - "| valid_batch_size | 100 | Number of validation examples evaluated at once. |\n", - "| shift_method | \"per_element_regression_shift\" | Method for shifting. |\n", - "| shift_options | energy_regularization: 1.0 | Regularization magnitude for energy regression. |\n", - "| shuffle_buffer_size | 1000 | Size of `tf.data` shuffle buffer. |\n", - "| pos_unit | Ang | Positional unit. |\n", - "| energy_unit | eV | Energy unit. |\n", - "| additional_properties_info | | Dictionary of property name, shape pairs. |\n", - "| **Model** | | |\n", - "| n_basis | 7 | Number of Gaussian basis functions. |\n", - "| n_radial | 5 | Number of contracted basis functions. |\n", - "| nn | [512, 512] | Hidden layers and units. |\n", - "| r_max | 6.0 | Maximum position of first basis function's mean. |\n", - "| r_min | 0.5 | Descriptor cutoff radius. |\n", - "| use_zbl | false | Use Zero-Body-Loss. |\n", - "| b_init | normal | Initialization scheme for biases. |\n", - "| descriptor_dtype | fp64 | Descriptor data type. |\n", - "| readout_dtype | fp32 | Readout data type. |\n", - "| scale_shift_dtype | fp32 | Scale/Shift data type. |\n", - "| **Loss** | | |\n", - "| loss_type | structures | Weighting scheme for atomic contributions. |\n", - "| name | energy | Quantity keyword. |\n", - "| weight | 1.0 | Weighting factor in loss function. |\n", - "| name | forces | Quantity keyword. |\n", - "| weight | 4.0 | Weighting factor in loss function. |\n", - "| **Metrics** | | |\n", - "| name | energy | Quantity keyword. |\n", - "| reductions | | List of reductions on target-prediction differences. |\n", - "| name | forces | Quantity keyword. |\n", - "| reductions | mae, mse | Reductions on target-prediction differences. |\n", - "| **Optimizer** | | |\n", - "| opt_name | adam | Optimizer name. |\n", - "| opt_kwargs | {} | Optimizer keyword arguments. |\n", - "| emb_lr | 0.03 | Learning rate for elemental embedding contraction coefficients. |\n", - "| nn_lr | 0.03 | Learning rate for neural network parameters. |\n", - "| scale_lr | 0.001 | Learning rate for elemental output scaling factors. |\n", - "| shift_lr | 0.05 | Learning rate for elemental output shifts. |\n", - "| zbl_lr | 0.001 | Learning rate for Zero-Body-Loss. |\n", - "| transition_begin | 0 | Training steps before linear learning rate schedule. |\n", - "| **Callbacks** | | |\n", - "| name | csv | Callback name. |\n", - "| **Progress Bar** | | |\n", - "| disable_epoch_pbar | false | Disable epoch progress bar. |\n", - "| disable_nl_pbar | false | Disable NL precomputation progress bar. |\n", - "| **Checkpoints** | | |\n", - "| ckpt_interval | 1 | Epochs between checkpoints. |\n", - "| base_model_checkpoint | null | Path to pre-trained model checkpoint. |\n", - "| reset_layers | [] | List of layers to reinitialize parameters. |\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Complete Configuration File\n", - " \n", - "```yaml\n", - "n_epochs: # Number of training epochs.\n", - "seed: 1 # Seed for initialising random numbers\n", - "patience: None # Number of epochs without improvement before trainings gets terminated.\n", - "n_models: 1 # Number of models to be trained at once.\n", - "n_jitted_steps: 1 # Number of train batches to be processed in a compiled loop. \n", - " # Can yield singificant speedups for small structures or small batch sizes.\n", - "\n", - "data:\n", - " directory: models/ # Path to the directory where the training results and checkpoints will be written.\n", - " experiment: apax # Name of the model. Distinguishes it from the other models trained in the same `directory`.\n", - " data_path: # Path to a single dataset file. Set either this or `val_data_path` and `train_data_path`.\n", - " train_data_path: # Path to a training dataset. Set this and `val_data_path` if your data comes pre-split.\n", - " val_data_path: # Path to a validation dataset. Set this and `train_data_path` if your data comes pre-split.\n", - " test_data_path: # Path to a test dataset. Set this, `train_data_path` and `val_data_path` if your data comes pre-split.\n", - "\n", - " n_train: 1000 # Number of training datapoints from `data_path`.\n", - " n_valid: 100 # Number of validation datapoints from `data_path`.\n", - "\n", - " batch_size: 32 # Number of training examples to be evaluated at once.\n", - " valid_batch_size: 100 # Number of validation examples to be evaluated at once.\n", - "\n", - " shift_method: \"per_element_regression_shift\"\n", - " shift_options:\n", - " energy_regularisation: 1.0 # Magnitude of the regularization in the per-element energy regression.\n", - " shuffle_buffer_size: 1000 # Size of the `tf.data` shuffle buffer.\n", - "\n", - " pos_unit: Ang\n", - " energy_unit: eV\n", - "\n", - " additional_properties_info: # Dict of property name, shape (ragged or fixed) pairs\n", - "\n", - "model:\n", - " n_basis: 7 # Number of uncontracted gaussian basis functions.\n", - " n_radial: 5 # Number of contracted basis functions.\n", - " nn: [512, 512] # Number of hidden layers and units in those layers.\n", - "\n", - " r_max: 6.0 # Position of the first uncontracted basis function's mean.\n", - " r_min: 0.5 # Cutoff radius of the descriptor.\n", - "\n", - " use_zbl: false # \n", - "\n", - " b_init: normal # Initialization scheme for the neural network biases. Either `normal` or `zeros`.\n", - " descriptor_dtype: fp64\n", - " readout_dtype: fp32\n", - " scale_shift_dtype: fp32\n", - "\n", - "loss:\n", - "- loss_type: structures # Weighting scheme for atomic contributions.\n", - " # See the MLIP package for reference 10.1088/2632-2153/abc9fe for details\n", - " name: energy # Keyword of the quantity e.g `energy`.\n", - " weight: 1.0 # Weighting factor in the overall loss function.\n", - "- loss_type: structures\n", - " name: forces\n", - " weight: 4.0\n", - "\n", - "metrics:\n", - "- name: energy # Keyword of the quantity e.g `energy`.\n", - " reductions: # List of reductions performed on the difference between target and predictions.\n", - " # Can be mae, mse, rmse for energies and forces. For forces it is also possible to use `angle`.\n", - " - mae\n", - "- name: forces\n", - " reductions:\n", - " - mae\n", - " - mse\n", - "\n", - "optimizer:\n", - " opt_name: adam # Name of the optimizer. Can be any `optax` optimizer.\n", - " opt_kwargs: {} # Optimizer keyword arguments. Passed to the `optax` optimizer.\n", - " emb_lr: 0.03 # Learning rate of the elemental embedding contraction coefficients.\n", - " nn_lr: 0.03 # Learning rate of the neural network parameters.\n", - " scale_lr: 0.001 # Learning rate of the elemental output scaling factors.\n", - " shift_lr: 0.05 # Learning rate of the elemental output shifts.\n", - " zbl_lr: 0.001 # \n", - " transition_begin: 0 # Number of training steps (not epochs) before the start of the linear learning rate schedule.\n", - "\n", - "callbacks:\n", - "- name: csv # Keyword of the callback used. Currently we implement \"csv\" and \"tensorboard\".\n", - "\n", - "progress_bar:\n", - " disable_epoch_pbar: false # Set to True to disable the epoch progress bar.\n", - " disable_nl_pbar: false # Set to True to disable the NL precomputation progress bar.\n", - "\n", - "\n", - "checkpoints:\n", - " ckpt_interval: 1 # Number of epochs between checkpoints.\n", - " \n", - " # The options below are used for transfer learning\n", - " base_model_checkpoint: null # Path to the folder containing a pre-trained model ckpt.\n", - " reset_layers: [] # List of layer names for which the parameters will be reinitialized.\n", - "\n", - "```" - ] - } - ], - "metadata": { - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 00f2fa9fe8d13e641d019e0cf93c9bcbf5de2073 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:44:42 +0000 Subject: [PATCH 183/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/cli/templates/md_config_minimal.yaml | 2 +- apax/cli/templates/train_config_full.yaml | 2 +- docs/source/_tutorials/index.rst | 2 +- docs/source/configs/full_configs.rst | 1 - docs/source/configs/index.rst | 2 +- docs/source/getting_started/index.rst | 2 +- docs/source/index.rst | 1 - docs/source/modules/config.rst | 2 +- 8 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apax/cli/templates/md_config_minimal.yaml b/apax/cli/templates/md_config_minimal.yaml index d59829fc..ed4016a7 100644 --- a/apax/cli/templates/md_config_minimal.yaml +++ b/apax/cli/templates/md_config_minimal.yaml @@ -21,4 +21,4 @@ load_momenta: false traj_name: md.h5 restart: true checkpoint_interval: 50_000 -disable_pbar: false \ No newline at end of file +disable_pbar: false diff --git a/apax/cli/templates/train_config_full.yaml b/apax/cli/templates/train_config_full.yaml index 4b5f7edf..42bfb526 100644 --- a/apax/cli/templates/train_config_full.yaml +++ b/apax/cli/templates/train_config_full.yaml @@ -94,4 +94,4 @@ checkpoints: progress_bar: disable_epoch_pbar: false - disable_batch_pbar: true \ No newline at end of file + disable_batch_pbar: true diff --git a/docs/source/_tutorials/index.rst b/docs/source/_tutorials/index.rst index 2231071d..e91c16a4 100644 --- a/docs/source/_tutorials/index.rst +++ b/docs/source/_tutorials/index.rst @@ -7,4 +7,4 @@ Tutorials 01_Model_Training 02_Molecular_dynamics 03_Transfer_Learning - 04_Batch_Data_Selection \ No newline at end of file + 04_Batch_Data_Selection diff --git a/docs/source/configs/full_configs.rst b/docs/source/configs/full_configs.rst index 56042d43..f8f5f06f 100644 --- a/docs/source/configs/full_configs.rst +++ b/docs/source/configs/full_configs.rst @@ -19,4 +19,3 @@ Full config can be downloaded :download:`here <../../../apax/cli/templates/md_co .. include:: ../../../apax/cli/templates/md_config_minimal.yaml :literal: - diff --git a/docs/source/configs/index.rst b/docs/source/configs/index.rst index 9cdcfeaa..79673ca5 100644 --- a/docs/source/configs/index.rst +++ b/docs/source/configs/index.rst @@ -4,4 +4,4 @@ Input Parameter .. toctree:: :maxdepth: 2 - full_configs \ No newline at end of file + full_configs diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index 5c2c49c0..7970eb5d 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -4,4 +4,4 @@ Getting Started .. toctree:: :maxdepth: 2 - install \ No newline at end of file + install diff --git a/docs/source/index.rst b/docs/source/index.rst index 3601e518..67ee7ab3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,4 +13,3 @@ It is based on `JAX `_ and uses `JaxMD Date: Wed, 10 Apr 2024 16:53:26 +0200 Subject: [PATCH 184/192] poetry update --- poetry.lock | 362 ++++++++++++++++++++++++---------------------------- 1 file changed, 168 insertions(+), 194 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4c136441..0a0cfcd1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. [[package]] name = "absl-py" @@ -205,16 +205,6 @@ files = [ ] [[package]] -<<<<<<< HEAD -name = "appnope" -version = "0.1.4" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = ">=3.6" -files = [ - {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, - {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, -======= name = "antlr4-python3-runtime" version = "4.9.3" description = "ANTLR 4.9.3 runtime for Python 3.7" @@ -233,7 +223,17 @@ python-versions = "*" files = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ->>>>>>>>> Temporary merge branch 2 +] + +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] [[package]] @@ -314,12 +314,6 @@ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" [[package]] -<<<<<<<<< Temporary merge branch 1 -name = "attrs" -version = "23.2.0" -description = "Classes Without Boilerplate" -optional = false -========= name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" @@ -369,8 +363,7 @@ files = [ name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -optional = true ->>>>>>>>> Temporary merge branch 2 +optional = false python-versions = ">=3.7" files = [ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, @@ -586,11 +579,7 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." -<<<<<<<<< Temporary merge branch 1 optional = false -========= -optional = true ->>>>>>>>> Temporary merge branch 2 python-versions = ">=3.8" files = [ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, @@ -1164,7 +1153,6 @@ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] -<<<<<<<<< Temporary merge branch 1 name = "debugpy" version = "1.8.1" description = "An implementation of the Debug Adapter Protocol for Python" @@ -1215,7 +1203,9 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -========= +] + +[[package]] name = "dictdiffer" version = "0.9.0" description = "Dictdiffer is a library that helps you to diff and patch dictionaries." @@ -1241,7 +1231,6 @@ python-versions = ">=3" files = [ {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, ->>>>>>>>> Temporary merge branch 2 ] [[package]] @@ -1290,6 +1279,13 @@ files = [ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa42a605d099ee7d41ba2b5fb75e21423951fd26e5d50583a00471238fb3021d"}, {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b7764de0d855338abefc6e3ee9fe40d301668310aa3baea3f778ff051f4393"}, {file = "dm_tree-0.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:a5d819c38c03f0bb5b3b3703c60e4b170355a0fc6b5819325bf3d4ceb3ae7e80"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea9e59e0451e7d29aece402d9f908f2e2a80922bcde2ebfd5dcb07750fcbfee8"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:94d3f0826311f45ee19b75f5b48c99466e4218a0489e81c0f0167bda50cacf22"}, + {file = "dm_tree-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:435227cf3c5dc63f4de054cf3d00183790bd9ead4c3623138c74dde7f67f521b"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09964470f76a5201aff2e8f9b26842976de7889300676f927930f6285e256760"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75c5d528bb992981c20793b6b453e91560784215dffb8a5440ba999753c14ceb"}, + {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a94aba18a35457a1b5cd716fd7b46c5dafdc4cf7869b4bae665b91c4682a8e"}, + {file = "dm_tree-0.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:96a548a406a6fb15fe58f6a30a57ff2f2aafbf25f05afab00c8f5e5977b6c715"}, {file = "dm_tree-0.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8c60a7eadab64c2278861f56bca320b2720f163dca9d7558103c3b77f2416571"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af4b3d372f2477dcd89a6e717e4a575ca35ccc20cc4454a8a4b6f8838a00672d"}, {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de287fabc464b8734be251e46e06aa9aa1001f34198da2b6ce07bd197172b9cb"}, @@ -1595,21 +1591,21 @@ tests = ["pytest (>=7,<8)", "pytest-asyncio (>=0.23.2,<1)", "pytest-benchmark", [[package]] name = "dvc-render" -version = "1.0.1" +version = "1.0.2" description = "Dvc Render" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "dvc-render-1.0.1.tar.gz", hash = "sha256:d7296869ea64c18ead9c99c46062ff116503b77a8d6e5c988f2d24716ea01d4a"}, - {file = "dvc_render-1.0.1-py3-none-any.whl", hash = "sha256:a8704e2048cd698d5ee19a611619f4f0e9c0a8508a2af3652198a2cb79b7a279"}, + {file = "dvc-render-1.0.2.tar.gz", hash = "sha256:40d1cd81760daf34b48fa8362b5002fcbe415e3cdbcf42369b6347d01497ffc0"}, + {file = "dvc_render-1.0.2-py3-none-any.whl", hash = "sha256:7e3e3cec1200fda41a99984190f14871f3cb878db7f94c853305056f69614ddb"}, ] [package.extras] -dev = ["dvc-render[docs]", "dvc-render[markdown]", "dvc-render[table]", "dvc-render[tests]"] -docs = ["mkdocs (==1.5.2)", "mkdocs-gen-files (==0.5.0)", "mkdocs-material (==9.3.1)", "mkdocs-section-index (==0.3.6)", "mkdocstrings-python (==1.6.3)"] +dev = ["dvc-render[docs,tests]", "mypy (==1.9.0)"] +docs = ["mkdocs (>=1.5.2,<2)", "mkdocs-gen-files (>=0.5.0,<1)", "mkdocs-material (>=9.3.1,<10)", "mkdocs-section-index (>=0.3.6,<1)", "mkdocstrings-python (>=1.6.3,<2)"] markdown = ["dvc-render[table]", "matplotlib"] table = ["flatten-dict (>=0.4.1,<1)", "tabulate (>=0.8.7)"] -tests = ["dvc-render[markdown]", "dvc-render[table]", "mypy (==1.2.0)", "pytest (==7.2.0)", "pytest-cov (==3.0.0)", "pytest-mock (==3.8.2)", "pytest-sugar (==0.9.7)"] +tests = ["dvc-render[markdown,table]", "pytest (>=7,<9)", "pytest-cov (>=4.1.0)", "pytest-mock", "pytest-sugar"] [[package]] name = "dvc-studio-client" @@ -1733,13 +1729,13 @@ test = ["pytest (>=6)"] [[package]] name = "execnet" -version = "2.0.2" +version = "2.1.1" description = "execnet: rapid multi-Python deployment" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, - {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, ] [package.extras] @@ -1775,13 +1771,13 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.13.3" +version = "3.13.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"}, - {file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"}, + {file = "filelock-3.13.4-py3-none-any.whl", hash = "sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f"}, + {file = "filelock-3.13.4.tar.gz", hash = "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"}, ] [package.extras] @@ -1807,13 +1803,13 @@ pyflakes = ">=2.5.0,<2.6.0" [[package]] name = "flask" -version = "3.0.2" +version = "3.0.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.8" files = [ - {file = "flask-3.0.2-py3-none-any.whl", hash = "sha256:3232e0e9c850d781933cf0207523d1ece087eb8d87b23777ae38456e2fbe7c6e"}, - {file = "flask-3.0.2.tar.gz", hash = "sha256:822c03f4b799204250a7ee84b1eddc40665395333973dfb9deebfe425fefcb7d"}, + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, ] [package.dependencies] @@ -1898,53 +1894,53 @@ psutil = ">=5.9.0" [[package]] name = "fonttools" -version = "4.50.0" +version = "4.51.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effd303fb422f8ce06543a36ca69148471144c534cc25f30e5be752bc4f46736"}, - {file = "fonttools-4.50.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7913992ab836f621d06aabac118fc258b9947a775a607e1a737eb3a91c360335"}, - {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0a1c5bd2f63da4043b63888534b52c5a1fd7ae187c8ffc64cbb7ae475b9dab"}, - {file = "fonttools-4.50.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d40fc98540fa5360e7ecf2c56ddf3c6e7dd04929543618fd7b5cc76e66390562"}, - {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fff65fbb7afe137bac3113827855e0204482727bddd00a806034ab0d3951d0d"}, - {file = "fonttools-4.50.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1aeae3dd2ee719074a9372c89ad94f7c581903306d76befdaca2a559f802472"}, - {file = "fonttools-4.50.0-cp310-cp310-win32.whl", hash = "sha256:e9623afa319405da33b43c85cceb0585a6f5d3a1d7c604daf4f7e1dd55c03d1f"}, - {file = "fonttools-4.50.0-cp310-cp310-win_amd64.whl", hash = "sha256:778c5f43e7e654ef7fe0605e80894930bc3a7772e2f496238e57218610140f54"}, - {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3dfb102e7f63b78c832e4539969167ffcc0375b013080e6472350965a5fe8048"}, - {file = "fonttools-4.50.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e58fe34cb379ba3d01d5d319d67dd3ce7ca9a47ad044ea2b22635cd2d1247fc"}, - {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c673ab40d15a442a4e6eb09bf007c1dda47c84ac1e2eecbdf359adacb799c24"}, - {file = "fonttools-4.50.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3ac35cdcd1a4c90c23a5200212c1bb74fa05833cc7c14291d7043a52ca2aaa"}, - {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8844e7a2c5f7ecf977e82eb6b3014f025c8b454e046d941ece05b768be5847ae"}, - {file = "fonttools-4.50.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f849bd3c5c2249b49c98eca5aaebb920d2bfd92b3c69e84ca9bddf133e9f83f0"}, - {file = "fonttools-4.50.0-cp311-cp311-win32.whl", hash = "sha256:39293ff231b36b035575e81c14626dfc14407a20de5262f9596c2cbb199c3625"}, - {file = "fonttools-4.50.0-cp311-cp311-win_amd64.whl", hash = "sha256:c33d5023523b44d3481624f840c8646656a1def7630ca562f222eb3ead16c438"}, - {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b4a886a6dbe60100ba1cd24de962f8cd18139bd32808da80de1fa9f9f27bf1dc"}, - {file = "fonttools-4.50.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b2ca1837bfbe5eafa11313dbc7edada79052709a1fffa10cea691210af4aa1fa"}, - {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0493dd97ac8977e48ffc1476b932b37c847cbb87fd68673dee5182004906828"}, - {file = "fonttools-4.50.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77844e2f1b0889120b6c222fc49b2b75c3d88b930615e98893b899b9352a27ea"}, - {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3566bfb8c55ed9100afe1ba6f0f12265cd63a1387b9661eb6031a1578a28bad1"}, - {file = "fonttools-4.50.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:35e10ddbc129cf61775d58a14f2d44121178d89874d32cae1eac722e687d9019"}, - {file = "fonttools-4.50.0-cp312-cp312-win32.whl", hash = "sha256:cc8140baf9fa8f9b903f2b393a6c413a220fa990264b215bf48484f3d0bf8710"}, - {file = "fonttools-4.50.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ccc85fd96373ab73c59833b824d7a73846670a0cb1f3afbaee2b2c426a8f931"}, - {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e270a406219af37581d96c810172001ec536e29e5593aa40d4c01cca3e145aa6"}, - {file = "fonttools-4.50.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac2463de667233372e9e1c7e9de3d914b708437ef52a3199fdbf5a60184f190c"}, - {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47abd6669195abe87c22750dbcd366dc3a0648f1b7c93c2baa97429c4dc1506e"}, - {file = "fonttools-4.50.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:074841375e2e3d559aecc86e1224caf78e8b8417bb391e7d2506412538f21adc"}, - {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0743fd2191ad7ab43d78cd747215b12033ddee24fa1e088605a3efe80d6984de"}, - {file = "fonttools-4.50.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3d7080cce7be5ed65bee3496f09f79a82865a514863197ff4d4d177389e981b0"}, - {file = "fonttools-4.50.0-cp38-cp38-win32.whl", hash = "sha256:a467ba4e2eadc1d5cc1a11d355abb945f680473fbe30d15617e104c81f483045"}, - {file = "fonttools-4.50.0-cp38-cp38-win_amd64.whl", hash = "sha256:f77e048f805e00870659d6318fd89ef28ca4ee16a22b4c5e1905b735495fc422"}, - {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b6245eafd553c4e9a0708e93be51392bd2288c773523892fbd616d33fd2fda59"}, - {file = "fonttools-4.50.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a4062cc7e8de26f1603323ef3ae2171c9d29c8a9f5e067d555a2813cd5c7a7e0"}, - {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34692850dfd64ba06af61e5791a441f664cb7d21e7b544e8f385718430e8f8e4"}, - {file = "fonttools-4.50.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678dd95f26a67e02c50dcb5bf250f95231d455642afbc65a3b0bcdacd4e4dd38"}, - {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f2ce7b0b295fe64ac0a85aef46a0f2614995774bd7bc643b85679c0283287f9"}, - {file = "fonttools-4.50.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d346f4dc2221bfb7ab652d1e37d327578434ce559baf7113b0f55768437fe6a0"}, - {file = "fonttools-4.50.0-cp39-cp39-win32.whl", hash = "sha256:a51eeaf52ba3afd70bf489be20e52fdfafe6c03d652b02477c6ce23c995222f4"}, - {file = "fonttools-4.50.0-cp39-cp39-win_amd64.whl", hash = "sha256:8639be40d583e5d9da67795aa3eeeda0488fb577a1d42ae11a5036f18fb16d93"}, - {file = "fonttools-4.50.0-py3-none-any.whl", hash = "sha256:48fa36da06247aa8282766cfd63efff1bb24e55f020f29a335939ed3844d20d3"}, - {file = "fonttools-4.50.0.tar.gz", hash = "sha256:fa5cf61058c7dbb104c2ac4e782bf1b2016a8cf2f69de6e4dd6a865d2c969bb5"}, + {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"}, + {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"}, + {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"}, + {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"}, + {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"}, + {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"}, + {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"}, + {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"}, + {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"}, + {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"}, + {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"}, + {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"}, + {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"}, + {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"}, + {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"}, + {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"}, + {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"}, + {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"}, + {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"}, + {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"}, + {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"}, + {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"}, + {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"}, + {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"}, + {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"}, + {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"}, + {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"}, + {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"}, + {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"}, + {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"}, + {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"}, + {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"}, + {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"}, + {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"}, + {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"}, + {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"}, + {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"}, + {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"}, + {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"}, + {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"}, + {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"}, + {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"}, ] [package.extras] @@ -2476,36 +2472,32 @@ tornado = ["tornado (>=0.2)"] [[package]] name = "h5py" -version = "3.10.0" +version = "3.11.0" description = "Read and write HDF5 files from Python" optional = false python-versions = ">=3.8" files = [ - {file = "h5py-3.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b963fb772964fc1d1563c57e4e2e874022ce11f75ddc6df1a626f42bd49ab99f"}, - {file = "h5py-3.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:012ab448590e3c4f5a8dd0f3533255bc57f80629bf7c5054cf4c87b30085063c"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:781a24263c1270a62cd67be59f293e62b76acfcc207afa6384961762bb88ea03"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f42e6c30698b520f0295d70157c4e202a9e402406f50dc08f5a7bc416b24e52d"}, - {file = "h5py-3.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:93dd840bd675787fc0b016f7a05fc6efe37312a08849d9dd4053fd0377b1357f"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2381e98af081b6df7f6db300cd88f88e740649d77736e4b53db522d8874bf2dc"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:667fe23ab33d5a8a6b77970b229e14ae3bb84e4ea3382cc08567a02e1499eedd"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90286b79abd085e4e65e07c1bd7ee65a0f15818ea107f44b175d2dfe1a4674b7"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c013d2e79c00f28ffd0cc24e68665ea03ae9069e167087b2adb5727d2736a52"}, - {file = "h5py-3.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:92273ce69ae4983dadb898fd4d3bea5eb90820df953b401282ee69ad648df684"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c97d03f87f215e7759a354460fb4b0d0f27001450b18b23e556e7856a0b21c3"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86df4c2de68257b8539a18646ceccdcf2c1ce6b1768ada16c8dcfb489eafae20"}, - {file = "h5py-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9ab36be991119a3ff32d0c7cbe5faf9b8d2375b5278b2aea64effbeba66039"}, - {file = "h5py-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c8e4fda19eb769e9a678592e67eaec3a2f069f7570c82d2da909c077aa94339"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:492305a074327e8d2513011fa9fffeb54ecb28a04ca4c4227d7e1e9616d35641"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9450464b458cca2c86252b624279115dcaa7260a40d3cb1594bf2b410a2bd1a3"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd6f6d1384a9f491732cee233b99cd4bfd6e838a8815cc86722f9d2ee64032af"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3074ec45d3dc6e178c6f96834cf8108bf4a60ccb5ab044e16909580352010a97"}, - {file = "h5py-3.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:212bb997a91e6a895ce5e2f365ba764debeaef5d2dca5c6fb7098d66607adf99"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dfc65ac21fa2f630323c92453cadbe8d4f504726ec42f6a56cf80c2f90d6c52"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4682b94fd36ab217352be438abd44c8f357c5449b8995e63886b431d260f3d3"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aece0e2e1ed2aab076c41802e50a0c3e5ef8816d60ece39107d68717d4559824"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43a61b2c2ad65b1fabc28802d133eed34debcc2c8b420cb213d3d4ef4d3e2229"}, - {file = "h5py-3.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:ae2f0201c950059676455daf92700eeb57dcf5caaf71b9e1328e6e6593601770"}, - {file = "h5py-3.10.0.tar.gz", hash = "sha256:d93adc48ceeb33347eb24a634fb787efc7ae4644e6ea4ba733d099605045c049"}, + {file = "h5py-3.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1625fd24ad6cfc9c1ccd44a66dac2396e7ee74940776792772819fc69f3a3731"}, + {file = "h5py-3.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c072655ad1d5fe9ef462445d3e77a8166cbfa5e599045f8aa3c19b75315f10e5"}, + {file = "h5py-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77b19a40788e3e362b54af4dcf9e6fde59ca016db2c61360aa30b47c7b7cef00"}, + {file = "h5py-3.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:ef4e2f338fc763f50a8113890f455e1a70acd42a4d083370ceb80c463d803972"}, + {file = "h5py-3.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd732a08187a9e2a6ecf9e8af713f1d68256ee0f7c8b652a32795670fb481ba"}, + {file = "h5py-3.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75bd7b3d93fbeee40860fd70cdc88df4464e06b70a5ad9ce1446f5f32eb84007"}, + {file = "h5py-3.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c416f8eb0daae39dabe71415cb531f95dce2d81e1f61a74537a50c63b28ab3"}, + {file = "h5py-3.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:083e0329ae534a264940d6513f47f5ada617da536d8dccbafc3026aefc33c90e"}, + {file = "h5py-3.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a76cae64080210389a571c7d13c94a1a6cf8cb75153044fd1f822a962c97aeab"}, + {file = "h5py-3.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3736fe21da2b7d8a13fe8fe415f1272d2a1ccdeff4849c1421d2fb30fd533bc"}, + {file = "h5py-3.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6ae84a14103e8dc19266ef4c3e5d7c00b68f21d07f2966f0ca7bdb6c2761fb"}, + {file = "h5py-3.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:21dbdc5343f53b2e25404673c4f00a3335aef25521bd5fa8c707ec3833934892"}, + {file = "h5py-3.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:754c0c2e373d13d6309f408325343b642eb0f40f1a6ad21779cfa9502209e150"}, + {file = "h5py-3.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:731839240c59ba219d4cb3bc5880d438248533366f102402cfa0621b71796b62"}, + {file = "h5py-3.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ec9df3dd2018904c4cc06331951e274f3f3fd091e6d6cc350aaa90fa9b42a76"}, + {file = "h5py-3.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:55106b04e2c83dfb73dc8732e9abad69d83a436b5b82b773481d95d17b9685e1"}, + {file = "h5py-3.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f4e025e852754ca833401777c25888acb96889ee2c27e7e629a19aee288833f0"}, + {file = "h5py-3.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c4b760082626120031d7902cd983d8c1f424cdba2809f1067511ef283629d4b"}, + {file = "h5py-3.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67462d0669f8f5459529de179f7771bd697389fcb3faab54d63bf788599a48ea"}, + {file = "h5py-3.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:d9c944d364688f827dc889cf83f1fca311caf4fa50b19f009d1f2b525edd33a3"}, + {file = "h5py-3.11.0.tar.gz", hash = "sha256:7b7e8f78072a2edec87c9836f25f34203fd492a4475709a18b417a33cfb21fa9"}, ] [package.dependencies] @@ -2847,13 +2839,13 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "joblib" -version = "1.3.2" +version = "1.4.0" description = "Lightweight pipelining with Python functions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"}, - {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"}, + {file = "joblib-1.4.0-py3-none-any.whl", hash = "sha256:42942470d4062537be4d54c83511186da1fc14ba354961a2114da91efa9a4ed7"}, + {file = "joblib-1.4.0.tar.gz", hash = "sha256:1eb0dc091919cd384490de890cb5dfd538410a6d4b3b54eef09fb8c50b409b1c"}, ] [[package]] @@ -3855,20 +3847,20 @@ files = [ [[package]] name = "networkx" -version = "3.2.1" +version = "3.3" description = "Python package for creating and manipulating graphs and networks" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, - {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, + {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, + {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, ] [package.extras] -default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] -developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] -doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +default = ["matplotlib (>=3.6)", "numpy (>=1.23)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["myst-nb (>=1.0)", "numpydoc (>=1.7)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=2.0)", "pygraphviz (>=1.12)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] @@ -4422,11 +4414,7 @@ test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", name = "prompt-toolkit" version = "3.0.43" description = "Library for building powerful interactive command lines in Python" -<<<<<<<<< Temporary merge branch 1 optional = false -========= -optional = true ->>>>>>>>> Temporary merge branch 2 python-versions = ">=3.7.0" files = [ {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, @@ -4608,11 +4596,7 @@ files = [ name = "pycparser" version = "2.22" description = "C parser in Python" -<<<<<<<<< Temporary merge branch 1 optional = false -========= -optional = true ->>>>>>>>> Temporary merge branch 2 python-versions = ">=3.8" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, @@ -4956,6 +4940,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -4963,8 +4948,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -4981,6 +4974,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -4988,6 +4982,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -5333,24 +5328,24 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, @@ -5358,7 +5353,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, @@ -5366,7 +5361,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, @@ -5374,7 +5369,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, @@ -5385,37 +5380,37 @@ files = [ [[package]] name = "scikit-learn" -version = "1.4.1.post1" +version = "1.4.2" description = "A set of python modules for machine learning and data mining" optional = false python-versions = ">=3.9" files = [ - {file = "scikit-learn-1.4.1.post1.tar.gz", hash = "sha256:93d3d496ff1965470f9977d05e5ec3376fb1e63b10e4fda5e39d23c2d8969a30"}, - {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c540aaf44729ab5cd4bd5e394f2b375e65ceaea9cdd8c195788e70433d91bbc5"}, - {file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4310bff71aa98b45b46cd26fa641309deb73a5d1c0461d181587ad4f30ea3c36"}, - {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f43dd527dabff5521af2786a2f8de5ba381e182ec7292663508901cf6ceaf6e"}, - {file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c02e27d65b0c7dc32f2c5eb601aaf5530b7a02bfbe92438188624524878336f2"}, - {file = "scikit_learn-1.4.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:629e09f772ad42f657ca60a1a52342eef786218dd20cf1369a3b8d085e55ef8f"}, - {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6145dfd9605b0b50ae72cdf72b61a2acd87501369a763b0d73d004710ebb76b5"}, - {file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1afed6951bc9d2053c6ee9a518a466cbc9b07c6a3f9d43bfe734192b6125d508"}, - {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce03506ccf5f96b7e9030fea7eb148999b254c44c10182ac55857bc9b5d4815f"}, - {file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ba516fcdc73d60e7f48cbb0bccb9acbdb21807de3651531208aac73c758e3ab"}, - {file = "scikit_learn-1.4.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:78cd27b4669513b50db4f683ef41ea35b5dddc797bd2bbd990d49897fd1c8a46"}, - {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a1e289f33f613cefe6707dead50db31930530dc386b6ccff176c786335a7b01c"}, - {file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0df87de9ce1c0140f2818beef310fb2e2afdc1e66fc9ad587965577f17733649"}, - {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712c1c69c45b58ef21635360b3d0a680ff7d83ac95b6f9b82cf9294070cda710"}, - {file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1754b0c2409d6ed5a3380512d0adcf182a01363c669033a2b55cca429ed86a81"}, - {file = "scikit_learn-1.4.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:1d491ef66e37f4e812db7e6c8286520c2c3fc61b34bf5e59b67b4ce528de93af"}, - {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aa0029b78ef59af22cfbd833e8ace8526e4df90212db7ceccbea582ebb5d6794"}, - {file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:14e4c88436ac96bf69eb6d746ac76a574c314a23c6961b7d344b38877f20fee1"}, - {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cd3a77c32879311f2aa93466d3c288c955ef71d191503cf0677c3340ae8ae0"}, - {file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a3ee19211ded1a52ee37b0a7b373a8bfc66f95353af058a210b692bd4cda0dd"}, - {file = "scikit_learn-1.4.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:234b6bda70fdcae9e4abbbe028582ce99c280458665a155eed0b820599377d25"}, + {file = "scikit-learn-1.4.2.tar.gz", hash = "sha256:daa1c471d95bad080c6e44b4946c9390a4842adc3082572c20e4f8884e39e959"}, + {file = "scikit_learn-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8539a41b3d6d1af82eb629f9c57f37428ff1481c1e34dddb3b9d7af8ede67ac5"}, + {file = "scikit_learn-1.4.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:68b8404841f944a4a1459b07198fa2edd41a82f189b44f3e1d55c104dbc2e40c"}, + {file = "scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81bf5d8bbe87643103334032dd82f7419bc8c8d02a763643a6b9a5c7288c5054"}, + {file = "scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f0ea5d0f693cb247a073d21a4123bdf4172e470e6d163c12b74cbb1536cf38"}, + {file = "scikit_learn-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:87440e2e188c87db80ea4023440923dccbd56fbc2d557b18ced00fef79da0727"}, + {file = "scikit_learn-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:45dee87ac5309bb82e3ea633955030df9bbcb8d2cdb30383c6cd483691c546cc"}, + {file = "scikit_learn-1.4.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1d0b25d9c651fd050555aadd57431b53d4cf664e749069da77f3d52c5ad14b3b"}, + {file = "scikit_learn-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0203c368058ab92efc6168a1507d388d41469c873e96ec220ca8e74079bf62e"}, + {file = "scikit_learn-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c62f2b124848a28fd695db5bc4da019287abf390bfce602ddc8aa1ec186aae"}, + {file = "scikit_learn-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:5cd7b524115499b18b63f0c96f4224eb885564937a0b3477531b2b63ce331904"}, + {file = "scikit_learn-1.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:90378e1747949f90c8f385898fff35d73193dfcaec3dd75d6b542f90c4e89755"}, + {file = "scikit_learn-1.4.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ff4effe5a1d4e8fed260a83a163f7dbf4f6087b54528d8880bab1d1377bd78be"}, + {file = "scikit_learn-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:671e2f0c3f2c15409dae4f282a3a619601fa824d2c820e5b608d9d775f91780c"}, + {file = "scikit_learn-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d36d0bc983336bbc1be22f9b686b50c964f593c8a9a913a792442af9bf4f5e68"}, + {file = "scikit_learn-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:d762070980c17ba3e9a4a1e043ba0518ce4c55152032f1af0ca6f39b376b5928"}, + {file = "scikit_learn-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9993d5e78a8148b1d0fdf5b15ed92452af5581734129998c26f481c46586d68"}, + {file = "scikit_learn-1.4.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:426d258fddac674fdf33f3cb2d54d26f49406e2599dbf9a32b4d1696091d4256"}, + {file = "scikit_learn-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5460a1a5b043ae5ae4596b3126a4ec33ccba1b51e7ca2c5d36dac2169f62ab1d"}, + {file = "scikit_learn-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d64ef6cb8c093d883e5a36c4766548d974898d378e395ba41a806d0e824db8"}, + {file = "scikit_learn-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:c97a50b05c194be9146d61fe87dbf8eac62b203d9e87a3ccc6ae9aed2dfaf361"}, ] [package.dependencies] joblib = ">=1.2.0" -numpy = ">=1.19.5,<2.0" +numpy = ">=1.19.5" scipy = ">=1.6.0" threadpoolctl = ">=2.0.0" @@ -5901,25 +5896,6 @@ doc = ["sphinx"] test = ["pytest", "pytest-cov"] [[package]] -<<<<<<<<< Temporary merge branch 1 -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] -========= name = "sqltrie" version = "0.11.0" description = "SQL-based prefix tree inspired by pygtrie and python-diskcache" @@ -5971,7 +5947,6 @@ files = [ [package.extras] widechars = ["wcwidth"] ->>>>>>>>> Temporary merge branch 2 [[package]] name = "tensorboard" @@ -6617,11 +6592,7 @@ testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] name = "wcwidth" version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" -<<<<<<<<< Temporary merge branch 1 optional = false -========= -optional = true ->>>>>>>>> Temporary merge branch 2 python-versions = "*" files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, @@ -6629,7 +6600,6 @@ files = [ ] [[package]] -<<<<<<<<< Temporary merge branch 1 name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" @@ -6641,8 +6611,6 @@ files = [ ] [[package]] -========= ->>>>>>>>> Temporary merge branch 2 name = "werkzeug" version = "3.0.2" description = "The comprehensive WSGI web application library." @@ -6699,6 +6667,16 @@ files = [ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecee4132c6cd2ce5308e21672015ddfed1ff975ad0ac8d27168ea82e71413f55"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2020f391008ef874c6d9e208b24f28e31bcb85ccff4f335f15a3251d222b92d9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2feecf86e1f7a86517cab34ae6c2f081fd2d0dac860cb0c0ded96d799d20b335"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:240b1686f38ae665d1b15475966fe0472f78e71b1b4903c143a842659c8e4cb9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9008dad07d71f68487c91e96579c8567c98ca4c3881b9b113bc7b33e9fd78b8"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6447e9f3ba72f8e2b985a1da758767698efa72723d5b59accefd716e9e8272bf"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acae32e13a4153809db37405f5eba5bac5fbe2e2ba61ab227926a22901051c0a"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49ef582b7a1152ae2766557f0550a9fcbf7bbd76f43fbdc94dd3bf07cc7168be"}, + {file = "wrapt-1.14.1-cp311-cp311-win32.whl", hash = "sha256:358fe87cc899c6bb0ddc185bf3dbfa4ba646f05b1b0b9b5a27c2cb92c2cea204"}, + {file = "wrapt-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:26046cd03936ae745a502abf44dac702a5e6880b2b01c29aea8ddf3353b68224"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, @@ -6974,8 +6952,4 @@ zntrack = ["zntrack"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -<<<<<<<<< Temporary merge branch 1 -content-hash = "e653af1e109d3da222e17f50a2519e9775c7392e5114dab48bffbb83bf5c58df" -========= -content-hash = "197f73688e0d11a4b3a4e6bdbecb096b905c13e4e4959333f8ffe1799d0e2826" ->>>>>>>>> Temporary merge branch 2 +content-hash = "c5e343f1c07c5e97a02d1024649acfd605bc95bcf01ac53a8ac03ab5718f25f0" From 8b8374675f4d01dbef84a3f2b37ee485f86e997e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:53:37 +0000 Subject: [PATCH 185/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/cli/templates/train_config_full.yaml | 2 +- docs/source/modules/train.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/cli/templates/train_config_full.yaml b/apax/cli/templates/train_config_full.yaml index 42bfb526..a5fe36d5 100644 --- a/apax/cli/templates/train_config_full.yaml +++ b/apax/cli/templates/train_config_full.yaml @@ -82,7 +82,7 @@ optimizer: zbl_lr: 0.001 transition_begin: 0 sam_rho: 0.0 - + callbacks: - name: csv diff --git a/docs/source/modules/train.rst b/docs/source/modules/train.rst index 9ba418df..d50dc2dc 100644 --- a/docs/source/modules/train.rst +++ b/docs/source/modules/train.rst @@ -18,6 +18,6 @@ Training .. automodule:: apax.train.run :members: - + .. automodule:: apax.train.trainer :members: From f0d7a7259684fbc269797a8a2bae3945ff865ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 10 Apr 2024 17:06:39 +0200 Subject: [PATCH 186/192] linting --- apax/config/common.py | 3 ++- apax/config/md_config.py | 15 ++++++++++----- apax/config/train_config.py | 18 ++++++++++++------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apax/config/common.py b/apax/config/common.py index 06ed2e90..7c28c4d1 100644 --- a/apax/config/common.py +++ b/apax/config/common.py @@ -20,7 +20,8 @@ def parse_config(config: Union[str, os.PathLike, dict], mode: str = "train") -> Path to the config file or a dictionary containing the config. mode: str, default = train - Defines if the config is validated for training ("train") or MD simulation("md"). + Defines if the config is validated for training ("train") + or MD simulation("md"). """ if isinstance(config, (str, os.PathLike)): with open(config, "r") as stream: diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 3d7ed223..83ee1023 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -95,7 +95,8 @@ class NPTOptions(NVTOptions, extra="forbid"): class MDConfig(BaseModel, frozen=True, extra="forbid"): """ - Configuration for a NHC molecular dynamics simulation. Full config :ref:`here `: + Configuration for a NHC molecular dynamics simulation. + Full config :ref:`here `: Parameters ---------- @@ -108,7 +109,8 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): duration : float, required | Total simulation time in fs. n_inner : int, default = 100 - | Number of compiled simulation steps (i.e. number of iterations of the `jax.lax.fori_loop` loop). Also determines atoms buffer size. + | Number of compiled simulation steps (i.e. number of iterations of the + | `jax.lax.fori_loop` loop). Also determines atoms buffer size. sampling_rate : int, default = 10 | Interval between saving frames. buffer_size : int, default = 100 @@ -116,7 +118,8 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): dr_threshold : float, default = 0.5 | Skin of the neighborlist. extra_capacity : int, default = 0 - | JaxMD allocates a maximal number of neighbors. This argument lets you add additional capacity to avoid recompilation. The default is usually fine. + | JaxMD allocates a maximal number of neighbors. This argument lets you add + | additional capacity to avoid recompilation. The default is usually fine. initial_structure : str, required | Path to the starting structure of the simulation. sim_dir : str, default = "." @@ -124,9 +127,11 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): traj_name : str, default = "md.h5" | Name of the trajectory file. restart : bool, default = True - | Whether the simulation should restart from the latest configuration in `traj_name`. + | Whether the simulation should restart from the latest configuration in + | `traj_name`. checkpoint_interval : int, default = 50_000 - | Number of time steps between saving full simulation state checkpoints. These will be loaded with the `restart` option. + | Number of time steps between saving full simulation state checkpoints. + | These will be loaded with the `restart` option. disable_pbar : bool, False | Disables the MD progressbar. """ diff --git a/apax/config/train_config.py b/apax/config/train_config.py index d771bf18..cff58b70 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -217,7 +217,8 @@ class OptimizerConfig(BaseModel, frozen=True, extra="forbid"): zbl_lr : NonNegativeFloat, default = 0.001 Learning rate of the ZBL correction parameters. transition_begin : int, default = 0 - Number of training steps (not epochs) before the start of the linear learning rate schedule. + Number of training steps (not epochs) before the start of the linear + learning rate schedule. opt_kwargs : dict, default = {} Optimizer keyword arguments. Passed to the `optax` optimizer. sam_rho : NonNegativeFloat, default = 0.0 @@ -245,7 +246,8 @@ class MetricsConfig(BaseModel, extra="forbid"): Keyword of the quantity, e.g., 'energy'. reductions : List[str] List of reductions performed on the difference between target and predictions. - Can be 'mae', 'mse', 'rmse' for energies and forces. For forces, 'angle' can also be used. + Can be 'mae', 'mse', 'rmse' for energies and forces. + For forces, 'angle' can also be used. """ name: str @@ -358,7 +360,8 @@ class CheckpointConfig(BaseModel, extra="forbid"): class Config(BaseModel, frozen=True, extra="forbid"): """ Main configuration of a apax training run. Parameter that are cofig classes will - be generated by parsing the config.yaml file and are specified as shown :ref:`here `: + be generated by parsing the config.yaml file and are specified + as shown :ref:`here `: Example ------- @@ -381,7 +384,8 @@ class Config(BaseModel, frozen=True, extra="forbid"): n_models : int, default = 1 | Number of models to be trained at once. n_jitted_steps : int, default = 1 - | Number of train batches to be processed in a compiled loop. Can yield singificant speedups for small structures or small batch sizes. + | Number of train batches to be processed in a compiled loop. + | Can yield singificant speedups for small structures or small batch sizes. data : :class:`.DataConfig` | Data configuration. model : :class:`.ModelConfig` @@ -393,13 +397,15 @@ class Config(BaseModel, frozen=True, extra="forbid"): optimizer : :class:`.OptimizerConfig` | Loss optimizer configuration. callbacks : List of various CallBack classes - | Possible callbacks are :class:`.CSVCallback`, :class:`.TBCallback`, :class:`.MLFlowCallback` + | Possible callbacks are :class:`.CSVCallback`, + | :class:`.TBCallback`, :class:`.MLFlowCallback` progress_bar : :class:`.TrainProgressbarConfig` | Progressbar configuration. checkpoints : :class:`.CheckpointConfig` | Checkpoint configuration. data_parallel : bool, default = True - | Automatically uses all available GPUs for data parallel training. Set to false to force single device training. + | Automatically uses all available GPUs for data parallel training. + | Set to false to force single device training. """ n_epochs: PositiveInt From 45809de9f6e033ff41fb44a0b90efd1370b5857b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 10 Apr 2024 17:16:57 +0200 Subject: [PATCH 187/192] updated extra capacity to non negative int --- apax/config/md_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 83ee1023..678648fe 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -4,7 +4,7 @@ from typing import Literal, Union import yaml -from pydantic import BaseModel, Field, PositiveFloat, PositiveInt +from pydantic import BaseModel, Field, PositiveFloat, PositiveInt, NonNegativeInt class NHCOptions(BaseModel, extra="forbid"): @@ -148,7 +148,7 @@ class MDConfig(BaseModel, frozen=True, extra="forbid"): sampling_rate: PositiveInt = 10 buffer_size: PositiveInt = 100 dr_threshold: PositiveFloat = 0.5 - extra_capacity: PositiveInt = 0 + extra_capacity: NonNegativeInt = 0 initial_structure: str load_momenta: bool = False From 196357cef2fe1811c37f90b9bcceb00e0c14cac9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 15:18:10 +0000 Subject: [PATCH 188/192] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- apax/config/md_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 678648fe..ddac646c 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -4,7 +4,7 @@ from typing import Literal, Union import yaml -from pydantic import BaseModel, Field, PositiveFloat, PositiveInt, NonNegativeInt +from pydantic import BaseModel, Field, NonNegativeInt, PositiveFloat, PositiveInt class NHCOptions(BaseModel, extra="forbid"): From 09ce3d143fa65a4d82cc00c256eb70c4c2b8b002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 10 Apr 2024 17:18:37 +0200 Subject: [PATCH 189/192] linting --- apax/config/md_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apax/config/md_config.py b/apax/config/md_config.py index 678648fe..ddac646c 100644 --- a/apax/config/md_config.py +++ b/apax/config/md_config.py @@ -4,7 +4,7 @@ from typing import Literal, Union import yaml -from pydantic import BaseModel, Field, PositiveFloat, PositiveInt, NonNegativeInt +from pydantic import BaseModel, Field, NonNegativeInt, PositiveFloat, PositiveInt class NHCOptions(BaseModel, extra="forbid"): From ee917643971a456862000708b5d2011c66aaf821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 10 Apr 2024 17:39:12 +0200 Subject: [PATCH 190/192] removed disfunctional docs action --- .github/workflows/documentation.yaml | 32 ---------------------------- docs/make_poetry.sh | 1 + 2 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 .github/workflows/documentation.yaml create mode 100644 docs/make_poetry.sh diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml deleted file mode 100644 index 28818685..00000000 --- a/.github/workflows/documentation.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: documentation - -on: - push: - schedule: - - cron: '14 3 * * 1' # at 03:14 on Monday. - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - - name: Run Poetry Image - uses: abatilo/actions-poetry@v2.0.0 - with: - poetry-version: 1.2.2 - - - name: Install Sphinx Dependencies - run: | - poetry --version - poetry install - - - name: Build documentation - run: | - cd docs - poetry run sphinx-build -b html source build \ No newline at end of file diff --git a/docs/make_poetry.sh b/docs/make_poetry.sh new file mode 100644 index 00000000..471b65d2 --- /dev/null +++ b/docs/make_poetry.sh @@ -0,0 +1 @@ +poetry run sphinx-build -b html source build From 2e190d167a1e056db0f51f5b21110fe8e5c9fb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20R=2E=20Sch=C3=A4fer?= Date: Wed, 10 Apr 2024 17:44:26 +0200 Subject: [PATCH 191/192] update version to 0.4.0 --- docs/source/conf.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0c822222..45f94b13 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,7 +15,7 @@ project = "Apax" copyright = "2023, Moritz Schäfer, Nico Segreto, Johannes Kästner" author = "Moritz Schäfer, Nico Segreto, Johannes Kästner" -release = "0.1.0" +release = "0.4.0" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml index 8fae38a3..7043c071 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "apax" -version = "0.3.0" +version = "0.4.0" description = "Atomistic Learned Potential Package in JAX" authors = ["Moritz René Schäfer ", "Nico Segreto "] keywords=["machine-learning", "interatomic potentials", "molecular-dynamics"] From 4fdde1ab80ac0ec8c17762d2662980ea1671a27a Mon Sep 17 00:00:00 2001 From: Tetracarbonylnickel Date: Wed, 10 Apr 2024 18:50:43 +0200 Subject: [PATCH 192/192] spell check --- apax/bal/api.py | 4 ++-- apax/config/train_config.py | 4 ++-- apax/data/input_pipeline.py | 2 +- apax/md/ase_calc.py | 2 +- apax/train/run.py | 2 +- apax/utils/jax_md_reduced/partition.py | 8 ++++---- apax/utils/jax_md_reduced/simulate.py | 4 ++-- apax/utils/jax_md_reduced/smap.py | 2 +- examples/01_Model_Training.ipynb | 6 +++--- examples/02_Molecular_Dynamics.ipynb | 4 ++-- examples/04_Batch_Data_Selection.ipynb | 4 ++-- tests/unit_tests/data/test_input_pipeline.py | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apax/bal/api.py b/apax/bal/api.py index 9f0571e4..f04c14ca 100644 --- a/apax/bal/api.py +++ b/apax/bal/api.py @@ -117,9 +117,9 @@ def kernel_selection( selection_method: Currently only "max_dist" is supported. feature_transforms: - Feature tranforms to be applied on top of the + Feature transforms to be applied on top of the base feature map transform. - Examples would include multiplcation with or addition of a constant. + Examples would include multiplication with or addition of a constant. selection_batch_size: Amount of new data points to be selected from `pool_atoms`. processing_batch_size: diff --git a/apax/config/train_config.py b/apax/config/train_config.py index cff58b70..388c0776 100644 --- a/apax/config/train_config.py +++ b/apax/config/train_config.py @@ -359,7 +359,7 @@ class CheckpointConfig(BaseModel, extra="forbid"): class Config(BaseModel, frozen=True, extra="forbid"): """ - Main configuration of a apax training run. Parameter that are cofig classes will + Main configuration of a apax training run. Parameter that are config classes will be generated by parsing the config.yaml file and are specified as shown :ref:`here `: @@ -385,7 +385,7 @@ class Config(BaseModel, frozen=True, extra="forbid"): | Number of models to be trained at once. n_jitted_steps : int, default = 1 | Number of train batches to be processed in a compiled loop. - | Can yield singificant speedups for small structures or small batch sizes. + | Can yield significant speedups for small structures or small batch sizes. data : :class:`.DataConfig` | Data configuration. model : :class:`.ModelConfig` diff --git a/apax/data/input_pipeline.py b/apax/data/input_pipeline.py index a6aceffc..9d75b4fd 100644 --- a/apax/data/input_pipeline.py +++ b/apax/data/input_pipeline.py @@ -18,7 +18,7 @@ def pad_nl(idx, offsets, max_neighbors): """ - Pad the neighbor list arrays to the maximal number of neighbors occuring. + Pad the neighbor list arrays to the maximal number of neighbors occurring. Parameters ---------- diff --git a/apax/md/ase_calc.py b/apax/md/ase_calc.py index 9637940f..57329af4 100644 --- a/apax/md/ase_calc.py +++ b/apax/md/ase_calc.py @@ -305,7 +305,7 @@ def batch_eval( unpadded_results = unpack_results(results, inputs) # for the last batch, the number of structures may be less - # than the batch_size, which is why we check this explicitely + # than the batch_size, which is why we check this explicitly num_strucutres_in_batch = results["energy"].shape[0] for j in range(num_strucutres_in_batch): atoms = atoms_list[i].copy() diff --git a/apax/train/run.py b/apax/train/run.py index da946c77..088a4d62 100644 --- a/apax/train/run.py +++ b/apax/train/run.py @@ -139,7 +139,7 @@ def run(user_config: Union[str, os.PathLike, dict], log_level="error"): Parameters ---------- user_config : str | os.PathLike | dict - training config full exmaple can be finde :ref:`here `: + training config full example can be find :ref:`here `: """ config = parse_config(user_config) diff --git a/apax/utils/jax_md_reduced/partition.py b/apax/utils/jax_md_reduced/partition.py index 36a7bafb..1a082605 100644 --- a/apax/utils/jax_md_reduced/partition.py +++ b/apax/utils/jax_md_reduced/partition.py @@ -161,7 +161,7 @@ def update(self, position: Array, **kwargs) -> "CellList": def kwarg_buffers(self): logging.warning( "kwarg_buffers renamed to named_buffer. The name " - "kwarg_buffers will be depricated." + "kwarg_buffers will be deprecated." ) return self.named_buffer @@ -179,7 +179,7 @@ class PartitionErrorCode(IntEnum): to allocate a new cell list. CELL_SIZE_TOO_SMALL: Indicates that the size of cells in a cell list was not large enough to properly capture particle interactions. This - indicates that it is necessary to allcoate a new cell list with larger + indicates that it is necessary to allocate a new cell list with larger cells. MALFORMED_BOX: Indicates that a box matrix was not properly upper triangular. @@ -242,7 +242,7 @@ class NeighborList: reference_position: The positions of particles when the neighbor list was constructed. This is used to decide whether the neighbor list ought to be updated. - error: An error code that is used to identify errors that occured during + error: An error code that is used to identify errors that occurred during neighbor list construction. See `PartitionError` and `PartitionErrorCode` for details. cell_list_capacity: An optional integer specifying the capacity of the cell @@ -317,7 +317,7 @@ class NeighborList: reference_position: The positions of particles when the neighbor list was constructed. This is used to decide whether the neighbor list ought to be updated. - error: An error code that is used to identify errors that occured during + error: An error code that is used to identify errors that occurred during neighbor list construction. See `PartitionError` and `PartitionErrorCode` for details. cell_list_capacity: An optional integer specifying the capacity of the cell diff --git a/apax/utils/jax_md_reduced/simulate.py b/apax/utils/jax_md_reduced/simulate.py index 5cd46c1f..c4a56901 100644 --- a/apax/utils/jax_md_reduced/simulate.py +++ b/apax/utils/jax_md_reduced/simulate.py @@ -1590,8 +1590,8 @@ def temp_csvr( Samples from the canonical ensemble in which the number of particles (N), the system volume (V), and the temperature (T) are held constant. CSVR - algorithmn samples the canonical distribution by rescaling the velocities - by a appropritely chosen random factor. At each timestep (dt) the rescaling + algorithm samples the canonical distribution by rescaling the velocities + by a appropriately chosen random factor. At each timestep (dt) the rescaling takes place and the rescaling factor is calculated using A7 Bussi et al. [#bussi2007]_. CSVR updates to the velocity are stochastic in nature and unlike the Berendsen thermostat it samples the true canonical diff --git a/apax/utils/jax_md_reduced/smap.py b/apax/utils/jax_md_reduced/smap.py index a4096cc5..7bb22f9b 100644 --- a/apax/utils/jax_md_reduced/smap.py +++ b/apax/utils/jax_md_reduced/smap.py @@ -160,7 +160,7 @@ def bond( an ndarray of distances or displacements of shape `[]` or `[d_in]` respectively. The metric can optionally take a floating point time as a third argument. - static_bonds: An ndarray of integer pairs wth shape `[b, 2]` where each + static_bonds: An ndarray of integer pairs with shape `[b, 2]` where each pair specifies a bond. `static_bonds` are baked into the returned compute function statically and cannot be changed after the fact. static_bond_types: An ndarray of integers of shape `[b]` specifying the diff --git a/examples/01_Model_Training.ipynb b/examples/01_Model_Training.ipynb index 9f3d012d..a0fc88d0 100644 --- a/examples/01_Model_Training.ipynb +++ b/examples/01_Model_Training.ipynb @@ -21,7 +21,7 @@ "\n", "## Acquiring a dataset\n", "\n", - "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/ethanol_ccsd_t.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be carefull the downloaded dataset has to be modified like in the `apax.untils.dataset.mod_md_datasets` function in order to be readable." + "You can obtain the benzene dataset with DFT labels either by running the following command or manually from this [link](http://www.quantum-machine.org/gdml/data/xyz/ethanol_ccsd_t.zip). Apax uses ASE to read in datasets, so make sure to convert your own data into an ASE readable format (extxyz, traj etc). Be careful the downloaded dataset has to be modified like in the `apax.utils.dataset.mod_md_datasets` function in order to be readable." ] }, { @@ -100,7 +100,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The following command create a minimal configuration file in the working directory. Full configuration file with descriptiond of the prameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/train_config_full.yaml)." + "The following command create a minimal configuration file in the working directory. Full configuration file with descriptiond of the parameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/train_config_full.yaml)." ] }, { @@ -291,7 +291,7 @@ "\n", "If training is interrupted for any reason, re-running the above `train` command will resume training from the latest checkpoint.\n", "\n", - "Furthermore, an Apax trianing can easily be started within a script." + "Furthermore, an Apax training can easily be started within a script." ] }, { diff --git a/examples/02_Molecular_Dynamics.ipynb b/examples/02_Molecular_Dynamics.ipynb index 59448fd8..41c5c659 100644 --- a/examples/02_Molecular_Dynamics.ipynb +++ b/examples/02_Molecular_Dynamics.ipynb @@ -244,7 +244,7 @@ "duration: 20_000 # fs\n", "initial_structure: project/benzene_mod.xyz\n", "```\n", - "Full configuration file with descriptiond of the prameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/md_config_minimal.yaml)." + "Full configuration file with descriptiond of the parameter can be found [here](https://github.com/apax-hub/apax/blob/main/apax/cli/templates/md_config_minimal.yaml)." ] }, { @@ -339,7 +339,7 @@ "metadata": {}, "source": [ "During the simulation, a progress bar tracks the instantaneous temperature at each outer step.\n", - "The simulation is followd by a small oh bondlength distribution analyses of the trajectory defined [here](#bondlength)." + "The simulation is followed by a small oh bondlength distribution analyses of the trajectory defined [here](#bondlength)." ] }, { diff --git a/examples/04_Batch_Data_Selection.ipynb b/examples/04_Batch_Data_Selection.ipynb index fa4f7435..1075a7c4 100644 --- a/examples/04_Batch_Data_Selection.ipynb +++ b/examples/04_Batch_Data_Selection.ipynb @@ -7,7 +7,7 @@ "# Batch Active Learning\n", "\n", "While it is possible to perform rudimentary data selection simply by randomly choosing samples, the batch of data thus drawn might not be the most informative one.\n", - "Choosing those samples whith the largest prediction uncertainties from trajectories often results in the selection of configurations from subsequent time steps.\n", + "Choosing those samples with the largest prediction uncertainties from trajectories often results in the selection of configurations from subsequent time steps.\n", "\n", "Batch selection methods can be constructed to select informative and diverse data, with or without following the underlying distribution.\n", "\n", @@ -392,7 +392,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As we can see below, the batch selection method only picks a few data points from the optimization part of the pool, indicating that during an optmization the structure of the molecule does not change very much.\n", + "As we can see below, the batch selection method only picks a few data points from the optimization part of the pool, indicating that during an optimization the structure of the molecule does not change very much.\n", "Hence, there are not many informative samples to be found in it." ] }, diff --git a/tests/unit_tests/data/test_input_pipeline.py b/tests/unit_tests/data/test_input_pipeline.py index 8d9209a5..05d7360e 100644 --- a/tests/unit_tests/data/test_input_pipeline.py +++ b/tests/unit_tests/data/test_input_pipeline.py @@ -10,7 +10,7 @@ from apax.utils.data import split_atoms, split_idxs from apax.utils.random import seed_py_np_tf -# TODO REENABLE LATER +# TODO RE-ENABLE LATER # @pytest.mark.parametrize( # "num_data, pbc, calc_results, external_labels", # (