From df2d8e965aee41f9f9f59ab8d46c3646d8baeaa4 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Thu, 1 Jul 2021 18:55:07 +0100 Subject: [PATCH 1/8] wrapping connectome method with standard matrix naming --- src/lib.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a13b9d6..f50daf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,15 @@ use indicatif::ParallelProgressIterator; use ndarray::parallel::prelude::*; use ndarray::prelude::*; -use pyo3::PyAny; use pyo3::exceptions::PyValueError; +use pyo3::PyAny; use std::error::Error; use numpy::{ IntoPyArray, PyArray1, PyArrayDyn, PyReadonlyArray1, PyReadonlyArray2, PyReadonlyArray3, }; -use pyo3::prelude::{pymodule, PyModule, PyResult, Python}; use pyo3::conversion::FromPyObject; - +use pyo3::prelude::{pymodule, PyModule, PyResult, Python}; //TODO: //1. Work out how to cargo doc to documentation @@ -26,7 +25,9 @@ impl FromPyObject<'_> for DistanceMode { match obj.extract().unwrap() { "euclidean" => Ok(DistanceMode::Euclidean), "manhattan" => Ok(DistanceMode::Manhattan), - _ => Err(PyValueError::new_err("Please provide a valid distance metric: [\"euclidean\", \"manhattan\"]")), + _ => Err(PyValueError::new_err( + "Please provide a valid distance metric: [\"euclidean\", \"manhattan\"]", + )), } } } @@ -108,6 +109,22 @@ fn rust_dtw(_py: Python<'_>, m: &PyModule) -> PyResult<()> { .into_pyarray(py)) } + #[pyfn(m, "dtw_matrix")] + fn wrapped_dtw_connectome_py<'py>( + py: Python<'py>, + connectome: PyReadonlyArray2<'_, f64>, + window: i32, + distance_mode: DistanceMode, + ) -> PyResult<&'py PyArray1> { + Ok(dtw_connectome( + connectome.as_array().view(), + &window, + select_distance(&distance_mode).unwrap(), + &distance_mode, + ) + .into_pyarray(py)) + } + /// Dynamic time warping on a 2D matrix representing an fMRI timeseries /// /// # Arguments From ffec6a2e55cbcd2e4cf82cf6db4705a68c68acc6 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood <45471420+FL33TW00D@users.noreply.github.com> Date: Thu, 1 Jul 2021 19:14:05 +0100 Subject: [PATCH 2/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca1a54f..bb6a588 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ rust_dtw.dtw( ) >>> 5.0990195 ``` -For more examples please see `examples/` +For more examples please see `examples/` or explore the [wiki](https://github.com/FL33TW00D/rustDTW/wiki). ## Developing From 7f62e2e4fa668358db8fe46802e425ba2c4f8e5c Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Tue, 6 Jul 2021 21:54:09 +0100 Subject: [PATCH 3/8] Adding age classification example --- .gitignore | 3 +- benches/my_benchmark.rs | 22 -- .../age_classification_comparison.ipynb | 224 ++++++++++++++++++ 3 files changed, 226 insertions(+), 23 deletions(-) delete mode 100644 benches/my_benchmark.rs create mode 100644 examples/classification/age_classification_comparison.ipynb diff --git a/.gitignore b/.gitignore index ad8670f..c636a15 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target -/examples/nilearn_cache/* +nilearn_cache +nilearn_data __pycache__/ diff --git a/benches/my_benchmark.rs b/benches/my_benchmark.rs deleted file mode 100644 index 68c8a75..0000000 --- a/benches/my_benchmark.rs +++ /dev/null @@ -1,22 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use rusty_dtw::*; - -fn criterion_benchmark(c: &mut Criterion) { - let config = Config { - mode: String::from("euclidean"), - window: 100, - vectorize: true, - }; - - let mut connectomes: Vec>> = vec![]; - for _ in 0..100 { - connectomes.push(construct_random_connectome(10)); - } - let distance = select_distance(&config.mode).unwrap(); - c.bench_function("dtw_connectome_list", |b| { - b.iter(|| dtw_connectomes(connectomes.clone(), &config.window, distance)) - }); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/examples/classification/age_classification_comparison.ipynb b/examples/classification/age_classification_comparison.ipynb new file mode 100644 index 0000000..bee5306 --- /dev/null +++ b/examples/classification/age_classification_comparison.ipynb @@ -0,0 +1,224 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "marked-jones", + "metadata": {}, + "outputs": [], + "source": [ + "#Modified version of the following script from nilearn: \n", + "#https://nilearn.github.io/auto_examples/03_connectivity/plot_group_level_connectivity.html\n", + "from nilearn import datasets\n", + "from tqdm.notebook import tqdm\n", + "\n", + "development_dataset = datasets.fetch_development_fmri()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "mighty-mitchell", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/numpy/lib/npyio.py:2349: VisibleDeprecationWarning: Reading unicode strings without specifying the encoding argument is deprecated. Set the encoding, use None for the system default.\n", + " output = genfromtxt(fname, **kwargs)\n" + ] + } + ], + "source": [ + "from nilearn import input_data\n", + "\n", + "msdl_data = datasets.fetch_atlas_msdl()\n", + "masker = input_data.NiftiMapsMasker(\n", + " msdl_data.maps, resampling_target=\"data\", t_r=2, detrend=True,\n", + " low_pass=.1, high_pass=.01, memory='nilearn_cache', memory_level=1).fit()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "weekly-balance", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "47f269cfc2b54b24b4207fa8bda2fb7c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Data has 122 children.\n" + ] + } + ], + "source": [ + "children = []\n", + "pooled_subjects = []\n", + "groups = [] # child or adult\n", + "for func_file, confound_file, phenotypic in tqdm(zip(\n", + " development_dataset.func,\n", + " development_dataset.confounds,\n", + " development_dataset.phenotypic)):\n", + " time_series = masker.transform(func_file, confounds=confound_file)\n", + " pooled_subjects.append(time_series)\n", + " if phenotypic['Child_Adult'] == 'child':\n", + " children.append(time_series)\n", + " groups.append(phenotypic['Child_Adult'])\n", + "\n", + "print('Data has {0} children.'.format(len(children)))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "stainless-revelation", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PROCESSING: dtw\n", + "PROCESSING: correlation\n", + "PROCESSING: partial correlation\n", + "PROCESSING: tangent\n" + ] + } + ], + "source": [ + "from sklearn.svm import LinearSVC\n", + "from sklearn.model_selection import StratifiedShuffleSplit\n", + "from sklearn.metrics import accuracy_score\n", + "from nilearn.connectome import ConnectivityMeasure\n", + "import rust_dtw\n", + "import numpy as np\n", + "\n", + "kinds = ['dtw', 'correlation', 'partial correlation', 'tangent']\n", + "_, classes = np.unique(groups, return_inverse=True)\n", + "cv = StratifiedShuffleSplit(n_splits=15, random_state=0, test_size=5)\n", + "pooled_subjects = np.asarray(pooled_subjects)\n", + "\n", + "scores = {}\n", + "for kind in kinds:\n", + " print('PROCESSING: ', kind)\n", + " scores[kind] = []\n", + " for train, test in cv.split(pooled_subjects, classes):\n", + " # *ConnectivityMeasure* can output the estimated subjects coefficients\n", + " # as a 1D arrays through the parameter *vectorize*.\n", + " if kind == 'dtw':\n", + " connectomes = rust_dtw.dtw_connectomes(\n", + " connectomes=pooled_subjects[train], \n", + " window=100, \n", + " vectorize=True, \n", + " distance_mode=\"euclidean\"\n", + " )\n", + " test_connectomes = rust_dtw.dtw_connectomes(\n", + " connectomes=pooled_subjects[test], \n", + " window=100, \n", + " vectorize=True, \n", + " distance_mode=\"euclidean\"\n", + " )\n", + " else:\n", + " connectivity = ConnectivityMeasure(kind=kind, vectorize=True)\n", + " connectomes = connectivity.fit_transform(pooled_subjects[train])\n", + " test_connectomes = connectivity.transform(pooled_subjects[test])\n", + " \n", + " classifier = LinearSVC(max_iter=10000).fit(connectomes, classes[train])\n", + " # make predictions for the left-out test subjects\n", + " predictions = classifier.predict(test_connectomes)\n", + " \n", + " # store the accuracy for this cross-validation fold\n", + " scores[kind].append(accuracy_score(classes[test], predictions))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "indian-calibration", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(0.9466666666666668, 'dtw'), (0.9066666666666667, 'correlation'), (0.92, 'partial correlation'), (0.9600000000000001, 'tangent')]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "mean_scores = [np.mean(scores[kind]) for kind in kinds]\n", + "print(list(zip(mean_scores, kinds) ))\n", + "scores_std = [np.std(scores[kind]) for kind in kinds]\n", + "\n", + "plt.figure(figsize=(10, 8))\n", + "positions = np.arange(len(kinds)) * .1 + .1\n", + "plt.barh(positions, mean_scores, align='center', height=.05, xerr=scores_std)\n", + "yticks = [k.replace(' ', '\\n') for k in kinds]\n", + "plt.yticks(positions, yticks)\n", + "plt.gca().grid(True)\n", + "plt.gca().set_axisbelow(True)\n", + "plt.gca().axvline(.8, color='red', linestyle='--')\n", + "plt.xlabel('Classification accuracy\\n(red line = chance level)')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "billion-charter", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 54da87dbfbdad010f3c01c13fdce359854005b15 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Wed, 7 Jul 2021 00:16:37 +0100 Subject: [PATCH 4/8] Adding ABIDE example --- .../classification/ABIDE_classification.ipynb | 502 ++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 examples/classification/ABIDE_classification.ipynb diff --git a/examples/classification/ABIDE_classification.ipynb b/examples/classification/ABIDE_classification.ipynb new file mode 100644 index 0000000..160f630 --- /dev/null +++ b/examples/classification/ABIDE_classification.ipynb @@ -0,0 +1,502 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "id": "spare-number", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "#Modified version of the following script from nilearn: \n", + "#https://nilearn.github.io/auto_examples/03_connectivity/plot_group_level_connectivity.html\n", + "from nilearn import datasets\n", + "from tqdm.notebook import tqdm\n", + "\n", + "abide_dataset = datasets.fetch_abide_pcp(n_subjects=200)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "frank-glenn", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['description', 'phenotypic', 'func_preproc'])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abide_dataset.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "difficult-multiple", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/numpy/lib/npyio.py:2349: VisibleDeprecationWarning: Reading unicode strings without specifying the encoding argument is deprecated. Set the encoding, use None for the system default.\n", + " output = genfromtxt(fname, **kwargs)\n" + ] + } + ], + "source": [ + "from nilearn import input_data\n", + "\n", + "msdl_data = datasets.fetch_atlas_msdl()\n", + "masker = input_data.NiftiMapsMasker(\n", + " msdl_data.maps, resampling_target=\"data\", t_r=2, detrend=True,\n", + " low_pass=.1, high_pass=.01, memory='nilearn_cache', memory_level=1).fit()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "cardiac-canadian", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ff312cd1ea494c188b7c4b2a694c82ab", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dataset has 200 subjects\n" + ] + } + ], + "source": [ + "pooled_subjects = []\n", + "groups = []\n", + "for func_file, dx in tqdm(zip(abide_dataset['func_preproc'], abide_dataset['phenotypic']['DX_GROUP'])):\n", + " time_series = masker.transform(func_file)\n", + " pooled_subjects.append(time_series)\n", + " groups.append(dx)\n", + "\n", + "print(f'Dataset has {len(pooled_subjects)} subjects')" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "varied-federation", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(196, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(206, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(78, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(176, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(146, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n", + "(296, 39)\n" + ] + } + ], + "source": [ + "for elem in pooled_subjects:\n", + " print(elem.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "occupied-photographer", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "200\n" + ] + } + ], + "source": [ + "print(len(groups))" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "structured-defensive", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PROCESSING: dtw\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/sklearn/svm/_base.py:983: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.\n", + " \"the number of iterations.\", ConvergenceWarning)\n", + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/sklearn/svm/_base.py:983: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.\n", + " \"the number of iterations.\", ConvergenceWarning)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PROCESSING: correlation\n", + "PROCESSING: partial correlation\n", + "PROCESSING: tangent\n" + ] + } + ], + "source": [ + "from sklearn.svm import LinearSVC\n", + "from sklearn.model_selection import StratifiedShuffleSplit\n", + "from sklearn.metrics import accuracy_score\n", + "from nilearn.connectome import ConnectivityMeasure\n", + "import rust_dtw\n", + "import numpy as np\n", + "\n", + "kinds = ['dtw', 'correlation', 'partial correlation', 'tangent']\n", + "# kinds = ['correlation']\n", + "_, classes = np.unique(groups, return_inverse=True)\n", + "cv = StratifiedShuffleSplit(n_splits=15, random_state=0, test_size=5)\n", + "pooled_subjects = np.asarray(pooled_subjects)\n", + "\n", + "scores = {}\n", + "for kind in kinds:\n", + " print('PROCESSING: ', kind)\n", + " scores[kind] = []\n", + " for train, test in cv.split(pooled_subjects, classes):\n", + " if kind == 'dtw':\n", + "# Having to do it this way because there are different time series configurations in the provided\n", + "# data. Otherwise rust_dtw.dtw_connectomes would be easier\n", + " connectomes = []\n", + " for subj in pooled_subjects[train]:\n", + " connectomes.append(\n", + " rust_dtw.dtw_connectome(\n", + " connectome=subj,\n", + " window=100, \n", + " distance_mode=\"euclidean\")\n", + " )\n", + " test_connectomes = []\n", + " for subj in pooled_subjects[test]:\n", + " test_connectomes.append(\n", + " rust_dtw.dtw_connectome(\n", + " connectome=subj,\n", + " window=100, \n", + " distance_mode=\"euclidean\")\n", + " )\n", + " else:\n", + " connectivity = ConnectivityMeasure(kind=kind, vectorize=True)\n", + " connectomes = connectivity.fit_transform(pooled_subjects[train])\n", + " test_connectomes = connectivity.transform(pooled_subjects[test])\n", + " \n", + " classifier = LinearSVC(max_iter=10000).fit(connectomes, classes[train])\n", + " # make predictions for the left-out test subjects\n", + " predictions = classifier.predict(test_connectomes)\n", + " \n", + " # store the accuracy for this cross-validation fold\n", + " scores[kind].append(accuracy_score(classes[test], predictions))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "optical-satisfaction", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(0.6933333333333332, 'dtw'), (0.6400000000000001, 'correlation'), (0.6133333333333334, 'partial correlation'), (0.6933333333333332, 'tangent')]\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsgAAAI4CAYAAAB3OR9vAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAAvWUlEQVR4nO3de5QnZX0n/veHi4MIggsqKCwYuURFnBBIFty47WX3qGhgI0GjqLiuGM26IZHsT7Oa48YbiZplowFFNouiriC6LmG9RMUWw2UCg8NllCEYEAgiF21Qucjl+f3RNbFshpmm6O9UT/N6nTNn+lvf6qr3t6kzvOeZp56q1loAAIBZm40dAAAAFhMFGQAAehRkAADoUZABAKBHQQYAgJ4txg6w2Gy//fZtjz32GDsGi8BPf/rTPOpRjxo7BouE64E+1wNJkjVrcu+992bzpz517CQMtHLlyptba4+du11BnuPxj398LrzwwrFjsAhMT09nampq7BgsEq4H+lwPJEmmpjIzM5Pt9YZNVlV9b13bTbEAAIAeI8gAAEN85CNZs2JFfn3sHCw4BRkAYIi9984d3//+2CmYAFMsAACG+Ju/yQ7nnjt2CiZAQQYAGOIDH8iup502dgomQEEGAIAeBRkAAHoUZAAA6FGQAQCgxzJvAABDnHJKvnPeeTlw7BwsOCPIAABD7Lpr7nrc48ZOwQQoyAAAQ5x6ah571lljp2ACFGQAgCFOOCFPPOOMsVMwAQoyAAD0KMgAANCjIAMAQI+CDAAAPdZBBgAY4vTTs/qcc/LMsXOw4IwgAwAMseOOuXu77cZOwQQoyAAAQ5x8cnb60pfGTsEEKMgAAEMoyEuWggwAAD3VWhs7w6KybOc9286vPm7sGACwqFx97MFjR1h8pqYyMzOT7VetGjsJA1XVytba/nO3G0EGAIAeBRkAAHqsgwwAMMQXvpBLzj47zxo7BwvOCDIAwBBbb537ttpq7BRMgIIMADDE8cfnCZ///NgpmABTLAAAhjjttDxuZmbsFEyAEWQAAOhRkAEAoEdBBgCAHgUZAAB63KQHADDE9HRWTU9nauwcLDgjyAAA0KMgAwAM8f73Z9dTTx07BRNgigUAwBBnnpkdrIO8JBlBBgCAHgUZAAB6FGQAAOhRkAEAhnjkI3PvsmVjp2AC3KQHADDEF7+YS62DvCQZQQYAgB4FGQBgiHe+M7t9/ONjp2ACTLEAABjia1/LY6yDvCQZQQYAgB4FGQAAehRkAADoMQcZAGCIHXbI3ffdN3YKJkBBBgAY4rOfzWrrIC9JplgAAECPEWQAgCHe+tY86ZprkqmpsZOwwCY2glxV21fVGyd1/Aejqo6uqq3HzgEALCHnnZftVq8eOwUTMMkpFtsnWRQFOcnRSRRkAAA2aJJTLI5N8uSqWpXk60n2TfKYJFsmeVtr7f9W1e5Jvpjk75IclOSfkhzSWrujqg5I8j+T3JfkK0le0Frbp6o27449lWRZkr9qrX2kqqaSvCPJzUn2SbIyyRFJ3pTkCUm+XlU3t9aePcHPDMCDdMOn3jJ2BOZh6vz3jR1h0Tlu1arcc889OWYRTbGYnp4eO8KSMMmC/JYk+7TWllfVFkm2bq3dVlU7Jjm/qs7o9tszye+01l5XVacleUmSTyT5X0le11o7r6qO7R33tUluba0dUFXLkpxTVX/bvfcrSZ6W5Pok5yR5ZmvtL6vqD5M8u7V287qCVtVRSY5KkkfstMcC/ggAYGmY8Ujl+7nnnnvSWltUPxsFeWFsrJv0Ksl7qupZmR0RfmKSx3fvXdVaW9V9vTLJ7lW1fZJtW2vndds/leRF3df/Lsm+VXVY93q7zJbsnyX5+9badUnSjVzvntnR6fVqrZ2Y5MQkWbbznm3QJwRgkJ1efuyGd2J0q449eOwIi88RR+QHP/hBVn3lK2MnYYFtrIL8iiSPTfKrrbW7q+rqJFt1793V2+/eJI/cwLEqyZtaa1/+hY2zUyzmHssqHQDAZHziE/nO9PQ/j/ixdEzyJr0fJ9m2+3q7JDd25fjZSXZb3ze21maS/Liqfr3b9LLe219O8oaq2jJJqmqvqnrUg8gCAAAPaGIjrK21W6rqnKq6LMkFSX65qi5NcmGSy+dxiNcm+WhV3ZfkG0lu7baflNmpExdVVSW5KcmhGzjWiUm+VFXXu0kPAFgQRx+dPa67zjrIS1C1tjin3FbVNq21n3RfvyXJzq2135/0eZftvGfb+dXHTfo0ALBJudoc5PubmsrMzEy2X7Vq7CQMVFUrW2v7z92+mOfoHlxVb81sxu8lOXLcOAAAPBws2oLcWjs1yalj5wAA4OFlkjfpAQDAJkdBBgAYYq+9cvsuu4ydgglYtFMsAAAWtRNPzBXT03nC2DlYcEaQAQCgxwgyAMAQRx2Vva6/3jrIS5CCDAAwxBVXZOuZmbFTMAGmWAAAQI+CDAAAPQoyAAD0KMgAAEMsX56f7LHH2CmYADfpAQAMcdxxuXJ6Oh4VsvQYQQYAgB4jyAAAQxxxRJ7ygx9YB3kJUpABAIa47rossw7ykmSKBQAA9CjIAADQoyADAECPOcgAAEMceGBuveaabD92DhacggwAMMR735urpqez29g5WHCmWAAAQI8RZACAIV7ykjztppuSs88eOwkLzAgyAMAQt9ySLW+7bewUTICCDAAAPQoyAAD0KMgAANDjJr05dn/0Zllz7MFjx2ARmJ6eztTU1NgxWCRcD/S5HkiSPPe5+dFVV1kHeQlSkAEAhnj72/O96ek8aewcLDhTLAAAoMcIMgDAEC94QZ7+wx8mK1aMnYQFZgQZAGCIO+7I5nfdNXYKJkBBBgCAHgUZAAB6FGQAAOhxkx4AwBAvelFu+e53rYO8BCnIAABDHHNMrp2ezpPHzsGCM8UCAAB6jCADAAwxNZXlMzPJqlVjJ2GBGUEGAIAeBRkAAHoUZAAA6FGQAQCgx016AABDHH54brziCusgL0FGkAEAhnjjG3P9oYeOnYIJUJABAIa4/fZsduedY6dgAkyxAAAY4oUvzL4zM8nznz92EhaYEWQAAOhRkAEAoEdBBgCAHgUZAAB63KQHADDEkUfmhssvtw7yEmQEGQBgiCOPzA1WsFiSFGQAgCFuvjlb3nrr2CmYAFMsAACGOOywPG1mJjnkkLGTsMCMIAMAQI+CDAAAPQoyAAD0KMgAANDjJj0AgCHe8Ib80+rV1kFeghRkAIAhXvrS3DQ9PXYKJsAUCwCAIa69NstuvHHsFEyAEWQAgCFe+co8ZWYmOfzwsZOwwIwgAwBAj4IMAAA9CjIAAPQoyAAA0OMmPQCAId785lx76aXWQV6CFGQAgCFe/OLcsu22Y6dgAkyxAAAYYs2aPPKaa8ZOwQQYQQYAGOL1r8/eMzPJq141dhIWmBFkAADoUZABAKBHQQYAgB4FGQAAetykBwAwxNvelu9dfLF1kJcgBRkAYIjnPS8/2kKVWopMsQAAGGLVqmxz5ZVjp2ACFGQAgCGOPjp7fOhDY6dgAhRkAADoUZABAKBHQQYAgB4FGQAAeqxNAgAwxHvek3+86KLsN3YOFpyCDAAwxEEH5baf/WzsFEyAKRYAAEOce24efdllY6dgAhRkAIAh/viP80snnTR2CiZAQQYAgB4FGQAAehRkAADoUZABAKDHMm8AAEMcd1yuvPDC7D92DhacggwAMMTy5fnJzMzYKZgAUywAAIb46lfzmJUrx07BBFRrbewMi8qynfdsO7/6uLFjALCJu/rYg8eOwKRNTWVmZibbr1o1dhIGqqqVrbX7zZIxggwAAD0KMgAA9CjIAADQoyADAECPZd4AAIb4yEeyZsWK/PrYOVhwCjIAwBB77507vv/9sVMwAaZYAAAM8Td/kx3OPXfsFEyAggwAMMQHPpBdTztt7BRMgIIMAAA9CjIAAPQoyAAA0KMgAwBAj2XeAACGOOWUfOe883Lg2DlYcEaQAQCG2HXX3PW4x42dgglQkAEAhjj11Dz2rLPGTsEEKMgAAEOccEKeeMYZY6dgAhRkAADoUZABAKBHQQYAgB4FGQAAeqyDDAAwxOmnZ/U55+SZY+dgwRlBBgAYYscdc/d2242dgglQkAEAhjj55Oz0pS+NnYIJUJABAIZQkJesTbIgV9WhVfXU3us/rarnbeB7Tq6qwyafDgCATdkmV5Craoskhyb554LcWvuT1tpXRwsFAMCSMUpBrqrdq+ryqvpkVX2nqk6vqq2r6k+q6oKquqyqTqyq6vafrqrjqurCJP9fkt9M8r6qWlVVT+6PDj/QMQAAYD7GHEHeO8nxrbWnJLktyRuTfKi1dkBrbZ8kj0zyot7+j2it7d9ae3eSM5L8UWtteWvtu3OOu75jAADAeo1ZkK9trZ3Tff2JJP86ybOrakVVXZrkOUme1tv/1Hked33HAABYGF/4Qi459tixUzABYz4opK3j9fFJ9m+tXVtV70iyVe/9n27ogFW11QaOAQCwMLbeOvdtpWYsRWOOIP/Lqjqw+/rlSf6u+/rmqtomyfpWnPhxkm3XsX3tVTqfYwAADHf88XnC5z8/dgomYMwR5DVJfq+q/jrJt5OckOQxSS5LckOSC9bzvZ9O8tGq+s/pleDW2kxVfXSexwB4WLrhU28ZO8LDwtT57xs7wpI3PT09boDTTsvjZmbGzcBEjFmQ72mtHTFn29u6X7+gtTY15/U56S3zluTI3nsPdIwj525bq6qOSnJUkjxipz02GBwANmRGcZq4sQvy8pmZ3HvvvaPnYOGNWZAXjdbaiUlOTJJlO+85d240wJKy08vdVLQxrDr24LEjMGnbb5+ZmZlMTU2NnYQFNkpBbq1dnWSfMc4NAADrsyiepFdV76iqYzawz4N+vDQAADxYExtBrqotWmv3PNDrAQ5NcmZmb+hLa+1PHlpCAICHYHo6q6anMzV2DhbcvEaQq+pVVXVJVV1cVad0j4o+q9v2tar6l91+J1fVh6tqRZI/X8frJ1fVl6pqZVV9s6p+eR3nel33qOiLq+qz3SOoD8r6Hy/93Kr6VlVdWlV/XVXLuu1XV9V/q6qLuvfudz4AAOjbYEGuqqdldlWI57TWnpHk95N8MMnHWmv7Jvlkkr/sfcsuSQ5qrf3hOl6fmORNrbVfTXJMZh/qMdfnukdFPyPJd5K8trV2bh7g8dLdw0FOTvLS1trTMzsq/obe8W5ure2X2WXk1juNAwBg3t7//ux66nwf9MumZD5TLJ6T5DOttZuTpLX2w+4BH7/VvX9Kkj/v7f+Z1tq9c193D+44KMlnqmrte8vWcb59qupdSbZPsk2SL28g395JrmqtXdG9/liS30tyXPf6c93vK3uZAQAemjPPzA6W81uSJjEHee4jode+3izJTGtt+Qa+/+Qkh7bWLq6qI5OHPLXnru73e2NZOwAANmA+c5DPSvLbVbVDklTVv0hybpKXde+/Isk3N3SQ1tptSa6qqt/ujlNV9Yx17Lptku9X1Zbdsdd6oMdLr0mye1WtfcLHK5N8Y4OfCgAA1mGDBbm1tjrJu5N8o6ouTvIXSd6U5DVVdUlmC+nvz/N8r0jy2u44q5Mcso593p5kRZJzklze2/7pJH/U3Yz35F6+O5O8JrNTNy5Ncl+SD88zDwAA/IJqzYPj+pbtvGfb+dXHjR0DgE3c1Z6kt/S94AW55Yc/zA4rVoydhIGqamVrbf+5283JBQAY4otfzKXWQV6SFsWT9AAAYLFQkAEAhnjnO7Pbxz8+dgomwBQLAIAhvva1PMY6yEuSEWQAAOhRkAEAoEdBBgCAHnOQAQCG2GGH3H3ffWOnYAIUZACAIT772ay2DvKSZIoFAAD0GEEGABjirW/Nk665JpmaGjsJC0xBBgAY4rzzsp11kJckUywAAKBHQQYAgB4FGQAAesxBBgAYYpddcteWW46dgglQkAEAhvjEJ/Kd6ek8fuwcLDhTLAAAoMcIMgDAEEcfnT2uu846yEuQggwAMMSqVdnGOshLkikWAADQYwR5jt0fvVnWHHvw2DFYBKanpzPln83ouB7ocz3A0mYEGQAAehRkAIAh9tort++yy9gpmABTLAAAhjjxxFwxPZ0njJ2DBWcEGQAAeowgAwAMcdRR2ev6662DvAQpyAAAQ1xxRba2DvKSZIoFAAD0KMgAANCjIAMAQI+CDAAwxPLl+ckee4ydgglwkx4AwBDHHZcrp6fjUSFLjxFkAADoMYIMADDEEUfkKT/4gXWQlyAFGQBgiOuuyzLrIC9JplgAAECPggwAAD0KMgAA9JiDDAAwxIEH5tZrrsn2Y+dgwSnIAABDvPe9uWp6OruNnYMFZ4oFAAD0GEEGABjiJS/J0266KTn77LGTsMCMIAMADHHLLdnyttvGTsEEKMgAANCjIAMAQI+CDAAAPW7SAwAY4rnPzY+uuso6yEuQggwAMMTb357vTU/nSWPnYMGZYgEAAD1GkAEAhnjBC/L0H/4wWbFi7CQsMCPIAABD3HFHNr/rrrFTMAEKMgAA9CjIAADQoyADAECPm/QAAIZ40Ytyy3e/ax3kJUhBBgAY4phjcu30dJ48dg4WnCkWAADQYwQZAGCIqaksn5lJVq0aOwkLzAgyAAD0KMgAANCjIAMAQI+CDAAAPW7SAwAY4vDDc+MVV1gHeQkyggwAMMQb35jrDz107BRMgIIMADDE7bdnszvvHDsFE2CKBQDAEC98YfadmUme//yxk7DAjCADAECPggwAAD0KMgAA9CjIAADQ4yY9AIAhjjwyN1x+uXWQlyAjyAAAQxx5ZG6wgsWSpCADAAxx883Z8tZbx07BBJhiAQAwxGGH5WkzM8khh4ydhAVmBBkAAHoUZAAA6FGQAQCgR0EGAIAeN+kBAAzxhjfkn1avtg7yEqQgAwAM8dKX5qbp6bFTMAGmWAAADHHttVl2441jp2ACjCADAAzxylfmKTMzyeGHj52EBWYEGQAAehRkAADoUZABAKBHQQYAgB436QEADPHmN+faSy+1DvISVK21sTMsKst23rPt/Orjxo4BALn62IPHjsAGTE9PZ2pqauwYDFRVK1tr+8/dbooFAMAQa9bkkddcM3YKJsAUCwCAIV7/+uw9M5O86lVjJ2GBGUEGAIAeBRkAAHoUZAAA6FGQAQCgx016AABDvO1t+d7FF1sHeQlSkAEAhnje8/KjLVSppcgUCwCAIVatyjZXXjl2CiZAQQYAGOLoo7PHhz40dgomQEEGAIAeBRkAAHoUZAAA6FGQAQCgx9okAABDvOc9+ceLLsp+Y+dgwSnIAABDHHRQbvvZz8ZOwQSYYgEAMMS55+bRl102dgomQEEGABjij/84v3TSSWOnYAIUZAAA6FGQAQCgR0EGAIAeBRkAAHos8wYAMMRxx+XKCy/M/mPnYMEpyAAAQyxfnp/MzIydggkwxQIAYIivfjWPWbly7BRMgIIMADDEu96V3U45ZewUTICCDAAAPQoyAAD0KMgAANCzKApyVb2jqo7ZwD6HVtVTe6//tKqeN/l0AAA8nExsmbeq2qK1ds8DvR7g0CRnJvl2krTW/uShJQQAeAg+8pGsWbEivz52DhbcvApyVb0qyTFJWpJLkrw9yV8n2THJTUle01q7pqpOTnJnkl9Jck5V/Ys5r/8qyV8leWyS25O8rrV2+ZxzvS7JUUkekeTKJK9MsjzJbyb5N1X1tiQv6TKc2Vo7vaqem+T93ee5IMkbWmt3VdXVST6W5MVJtkzy23PPBzCGGz71lrEjsAmYOv99Y0dgA2ZmZrL9X//1qBmmp6dHPf9StMGCXFVPS/K2JAe11m7uSu/HknystfaxqvoPSf4ysyO8SbJLt++9XWHuv/5akt9trf1DVf16kuOTPGfOKT/XWvtod+53JXlta+2DVXVGukLcvbc231ZJTk7y3NbaFVX18SRvSHJcd7ybW2v7VdUbM1vy/+M6PuNRmS3lecROe2zoRwIAG8WMh1Asas+69dbcd999+buRcyjIC28+I8jPSfKZ1trNSdJa+2FVHZjkt7r3T0ny5739P9Nau3fu66raJslBST6zttwmWbaO8+3TFePtk2yT5MsbyLd3kqtaa1d0rz+W5Pfy84L8ue73lb3Mv6C1dmKSE5Nk2c57tg2cD+Ah2+nlx44dgU3AqmMPHjsC6zM1NTuCvGrV2ElYYJOYg/zTB3i9WZKZ1tryDXz/yUkOba1dXFVHJpl6iHnu6n6/Nx6tDQDABsxnFYuzkvx2Ve2QJN0Ui3OTvKx7/xVJvrmhg7TWbktyVVX9dnecqqpnrGPXbZN8v6q27I691o+79+Zak2T3qlo7N+KVSb6xwU8FAADrsMGC3FpbneTdSb5RVRcn+Yskb0rymqq6JLOF9Pfneb5XJHltd5zVSQ5Zxz5vT7IiyTlJ+jfUfTrJH1XVt6rqyb18dyZ5TWanblya5L4kH55nHgAA+AXVmim3fct23rPt/Orjxo4BALnaHOTFzRzkTV5VrWyt7T93uzm5AABDnHJKvnPeeTlw7BwsuEXxJD0AgE3Orrvmrsc9buwUTICCDAAwxKmn5rFnnTV2CiZAQQYAGOKEE/LEM84YOwUToCADAECPggwAAD0KMgAA9CjIAADQYx1kAIAhTj89q885J88cOwcLzggyAMAQO+6Yu7fbbuwUTICCDAAwxMknZ6cvfWnsFEyAggwAMISCvGQpyAAA0KMgAwBAj4IMAAA9CjIAAPRYBxkAYIgvfCGXnH12njV2DhacEWQAgCG23jr3bbXV2CmYAAUZAGCI44/PEz7/+bFTMAGmWAAADHHaaXnczMzYKZgAI8gAANCjIAMAQI+CDAAAPQoyAAD0uEkPAGCI6emsmp7O1Ng5WHBGkAEAoEdBBgAY4v3vz66nnjp2CibAFIs5dn/0Zllz7MFjx2ARmJ6eztTU1NgxWCRcD/S5HkiSnHlmdrAO8pJkBBkAAHoUZAAA6FGQAQCgR0EGABjikY/MvcuWjZ2CCXCTHgDAEF/8Yi61DvKSZAQZAAB6FGQAgCHe+c7s9vGPj52CCTDFAgBgiK99LY+xDvKSZAQZAAB6FGQAAOhRkAEAoMccZACAIXbYIXffd9/YKZgABRkAYIjPfjarrYO8JJliAQAAPUaQAQCGeOtb86RrrkmmpsZOwgJTkAEAhjjvvGxnHeQlyRQLAADoUZABAKBHQQYAgB5zkAEAhthll9y15ZZjp2ACFGQAgCE+8Yl8Z3o6jx87BwvOFAsAAOgxggwAMMTRR2eP666zDvISpCADAAyxalW2sQ7ykmSKBQAA9CjIAADQoyADAECPggwAMMRee+X2XXYZOwUT4CY9AIAhTjwxV0xP5wlj52DBGUEGAIAeI8gAAEMcdVT2uv566yAvQQoyAMAQV1yRra2DvCSZYgEAAD0KMgAA9CjIAADQoyADAAyxfHl+ssceY6dgAtykBwAwxHHH5crp6XhUyNJjBBkAAHqMIAMADHHEEXnKD35gHeQlSEEGABjiuuuyzDrIS5IpFgAA0KMgAwBAj4IMAAA95iADAAxx4IG59Zprsv3YOVhwCjIAwBDvfW+ump7ObmPnYMGZYgEAAD1GkAEAhnjJS/K0m25Kzj577CQsMCPIAABD3HJLtrzttrFTMAEKMgAA9CjIAADQoyADAECPm/QAAIZ47nPzo6uusg7yEqQgAwAM8fa353vT03nS2DlYcKZYAABAjxFkAIAhXvCCPP2HP0xWrBg7CQvMCDIAwBB33JHN77pr7BRMgIIMAAA9CjIAAPQoyAAA0OMmPQCAIV70otzy3e9aB3kJUpABAIY45phcOz2dJ4+dgwVnigUAAPQYQQYAGGJqKstnZpJVq8ZOwgIzggwAAD0KMgAA9FRrbewMi8qynfdsO7/6uLFjAMCicvWxB48dYfGZmsrMzEy2N8Vik1VVK1tr+8/dbgQZAAB63KQHADDE4YfnxiuusA7yEmQEGQBgiDe+MdcfeujYKZgABRkAYIjbb89md945dgomwBQLAIAhXvjC7Dszkzz/+WMnYYEZQQYAgB4FGQAAehRkAADoUZABAKDHTXoAAEMceWRuuPxy6yAvQUaQAQCGOPLI3GAFiyVJQQYAGOLmm7PlrbeOnYIJMMUCAGCIww7L02ZmkkMOGTsJC8wIMgAA9CjIAADQoyADAECPggwAAD1u0gMAGOINb8g/rV5tHeQlSEEGABjipS/NTdPTY6dgAkyxAAAY4tprs+zGG8dOwQQYQQYAGOKVr8xTZmaSww8fOwkLzAgyAAD0KMgAANCjIAMAQI+CDAAAPW7SAwAY4s1vzrWXXmod5CVIQQYAGOLFL84t2247dgomwBQLAIAh1qzJI6+5ZuwUTIARZACAIV7/+uw9M5O86lVjJ2GBGUEGAICeTXoEuarekeQnSW5O8rettevHTQQAwKZuqYwgH5nkCWOHAABg07fJjSBX1X9N8uokNya5NsnKJPsn+WRV3ZHkTUn+oLX2W1V1SJJPJ9kus38Z+HZr7ZfGSQ4weTd86i1jR2CJmjr/fWNHWHSOW7Uq99xzT46Zmho7yiZtenp67Aj3s0kV5Kr61SQvS7I8s9kvymxBvjDJMa21C6tqiyQf677lN5JcluSAbv8VD3Dco5IclSSP2GmPCX4CANg0zczMjB1h0Tlhhx1y3333+dk8RAryQ/cbSf5Pa+32JKmqM+bu0Fq7p6q+W1VPSfJrSf4iybOSbJ7km+s6aGvtxCQnJsmynfdsE8oOMHE7vfzYsSOwRK069uCxIyxK09PT+agR5CVnqcxBnuvsJC9IcneSryb5192vdRZkAIAHbdWqbHPllWOnYAI2tYJ8dpJDq+qRVbVtkhd323+cpP8om28mOTrJea21m5LskGTvzE63AAB46I4+Ont86ENjp2ACNqkpFq21i6rq1CQXZ/YmvQu6t05O8uHuJr0DMzvX+PGZLdRJckmSnVprpk8AALBem1RBTpLW2ruTvHsdb312zutlve85aqKhAABYMja1KRYAADBRCjIAAPRsclMsAAAWhfe8J/940UXZb+wcLDgFGQBgiIMOym0/+9nYKZgAUywAAIY499w8+jIryC5FCjIAwBB//Mf5pZNOGjsFE6AgAwBAj4IMAAA9CjIAAPQoyAAA0GOZNwCAIY47LldeeGH2HzsHC05BBgAYYvny/GRmZuwUTIApFgAAQ3z1q3nMypVjp2ACFGQAgCHe9a7sdsopY6dgAhRkAADoUZABAKBHQQYAgB4FGQAAeizzBgAwxEc+kjUrVuTXx87BglOQAQCG2Hvv3PH974+dggkwxQIAYIi/+ZvscO65Y6dgAhRkAIAhPvCB7HraaWOnYAIUZAAA6FGQAQCgR0EGAIAeBRkAAHos8wYAMMQpp+Q7552XA8fOwYJTkOfY/dGbZc2xB48dg0Vgeno6U1NTY8dgkXA90Od6IEmy666567vfHTsFE2CKBQDAEKeemseeddbYKZgABRkAYIgTTsgTzzhj7BRMgIIMAAA9CjIAAPQoyAAA0KMgAwBAj2XeAACGOP30rD7nnDxz7BwsOCPIAABD7Lhj7t5uu7FTMAEKMgDAECefnJ2+9KWxUzABCjIAwBAK8pKlIAMAQI+CDAAAPQoyAAD0KMgAANBjHWQAgCG+8IVccvbZedbYOVhwRpABAIbYeuvct9VWY6dgAhRkAIAhjj8+T/j858dOwQSYYgEAMMRpp+VxMzNjp2ACjCADAECPggwAAD0KMgAA9CjIAADQU621sTMsKlX14yRrxs7BorBjkpvHDsGi4Xqgz/XAWq6FTdturbXHzt1oFYv7W9Na23/sEIyvqi50LbCW64E+1wNruRaWJlMsAACgR0EGAIAeBfn+Thw7AIuGa4E+1wN9rgfWci0sQW7SAwCAHiPIAADQoyADAEDPw7YgV9Xzq2pNVV1ZVW9Zx/vLqurU7v0VVbX7CDHZCOZxLfxhVX27qi6pqq9V1W5j5GTj2ND10NvvJVXVqsryTkvUfK6Fqjq8+/NhdVV9amNnZOOZx/8r/mVVfb2qvtX9/+KFY+RkYTws5yBX1eZJrkjyb5Ncl+SCJL/TWvt2b583Jtm3tfa7VfWyJP++tfbSUQIzMfO8Fp6dZEVr7faqekOSKdfC0jSf66Hbb9sk/y/JI5L8p9bahRs7K5M1zz8b9kxyWpLntNZ+VFWPa63dOEpgJmqe18OJSb7VWjuhqp6a5Auttd3HyMtD93AdQf61JFe21v6xtfazJJ9OcsicfQ5J8rHu69OTPLeqaiNmZOPY4LXQWvt6a+327uX5SXbZyBnZeObzZ0OSvDPJnyW5c2OGY6Oaz7XwuiR/1Vr7UZIox0vafK6HluTR3dfbJbl+I+ZjgT1cC/ITk1zbe31dt22d+7TW7klya5IdNko6Nqb5XAt9r03yxYkmYkwbvB6qar8ku7bW/t/GDMZGN58/G/ZKsldVnVNV51fV8zdaOja2+VwP70hyRFVdl+QLSd60caIxCR41DfNUVUck2T/Jvxk7C+Ooqs2S/EWSI0eOwuKwRZI9k0xl9l+Wzq6qp7fWZsYMxWh+J8nJrbUPVNWBSU6pqn1aa/eNHYwH7+E6gvxPSXbtvd6l27bOfapqi8z+c8ktGyUdG9N8roVU1fOS/Nckv9lau2sjZWPj29D1sG2SfZJMV9XVSf5VkjPcqLckzefPhuuSnNFau7u1dlVm56juuZHysXHN53p4bWbnpKe1dl6SrZLsuFHSseAergX5giR7VtWTquoRSV6W5Iw5+5yR5NXd14clOas9HO9oXPo2eC1U1a8k+Uhmy7E5hkvbeq+H1tqtrbUdW2u7dzffnJ/Z68JNekvPfP4/8fnMjh6nqnbM7JSLf9yIGdl45nM9XJPkuUlSVU/JbEG+aaOmZME8LAtyN6f4PyX5cpLvJDmttba6qv60qn6z2+1/Jtmhqq5M8odJHnC5JzZd87wW3pdkmySfqapVVTX3D0WWiHleDzwMzPNa+HKSW6rq20m+nuSPWmv+pXEJmuf18OYkr6uqi5P87yRHGljbdD0sl3kDAIAH8rAcQQYAgAeiIAMAQI+CDAAAPQoyAAD0KMgAANCjIANsQFXtVFWfrqrvVtXKqvpCVe1VVbtX1WULeJ4/7R5Kk6r6japa3S0t+MSqOn3gMY+sqif0Xp9UVU9dqMwAS5Fl3gDWo6oqyblJPtZa+3C37RlJHp3k2iRnttb2mcB5P5zk71prn3iIx5lOcsym/DCTqtq8tXbv2DmAhw8jyADr9+wkd68tx0nSWru4tfbN/k7daPI3q+qi7tdB3fadq+rsbiT4sm5kePOqOrl7fWlV/UG378lVdVhV/cckhyd5Z1V9sj9S3X3v+7vvvaSq3tRt/5OquqDbfmLNOizJ/kk+2Z3/kVU1vfbR2FX1O935L6uqP+t9lp9U1bur6uKqOr+qHj/3h1JVv1ZV51XVt6rq3KraewP5Duj2u7iq/r6qtu1Gtz/UO+aZVTXVy/CB7qELB67r83X77VFVX+2Oe1FVPbmqPl5Vh/aO+8mqOmTgf3/gYUhBBli/fZKsnMd+Nyb5t621/ZK8NMlfdttfnuTLrbXlSZ6RZFWS5Ume2Frbp7X29CT/q3+g1tpJmX2M7R+11l4x5zxHJdk9yfLW2r5JPtlt/1Br7YBuNPuRSV7UWjs9yYVJXtFaW95au2PtQbppF3+W5DldngN6pfJRSc5vrT0jydlJXreOz3t5kt9orf1Kkj9J8p4Hylezj+Y9Ncnvd8d8XpI77n/IX/CoJCtaa89orf3duj5ft98nk/xVd9yDknw/s09CPbL7nNt12//fBs4H8M8UZICFsWWSj1bVpUk+k2TtPN8Lkrymqt6R5OmttR8n+cckv1RVH6yq5ye57UGc53lJPtI9+jattR92259dVSu68z8nydM2cJwDkky31m7qjvXJJM/q3vtZkjO7r1dmtvDOtV1mH79+WZL/3jvfuvLtneT7rbULum23rX1/Pe5N8tne6/t9vqraNrN/0fg/3XHvbK3d3lr7RpI9q+qxSX4nyWfncT6Af6YgA6zf6iS/Oo/9/iDJDzI7Srx/kkckSWvt7MwWz39KcnJVvaq19qNuv+kkv5vkpIcSsKq2SnJ8ksO6EemPJtnqIRzy7vbzG1TuTbLFOvZ5Z5KvdyO6Lx54vnvyi/8f6h/jzrXzjgd+vo8nOSLJa5L89YBswMOYggywfmclWVZVR63dUFX7VtVvzNlvu8yOkt6X5JVJNu/23S3JD1prH81sEd6vqnZMsllr7bNJ3pZkvweR5ytJXl9VW3TH/xf5eVm8uaq2SXJYb/8fJ9l2Hcf5+yT/pqp2rKrNMzvS+o0HkWO7zJb+pJvOsJ58a5LsXFUHdNu27d6/OsnyqtqsqnZN8msPcK51fr5uNP66tVNDqmpZVW3d7XtykqO7/b79ID4XgIIMsD7dSOq/T/K8ml3mbXWS9ya5Yc6uxyd5dXdT2S8n+Wm3fSrJxVX1rczOTf4fSZ6YZLqqViX5RJK3PohIJyW5Jskl3ble3lqbyeyo6mVJvpzZaR1rnZzkw2tv0ut9ru8neUuSrye5OMnK1tr/fRA5/jzJe7vP1R9hXle+n2X2s3+w2/aVzJbec5JcleTbmZ2zfdG6TrSBz/fKJP+5qi7J7GojO3Xf84Mk38mc+d0A82GZNwCWnG4k+dIk+7XWbh07D7BpMYIMwJJSsw9b+U6SDyrHwBBGkAEAoMcIMgAA9CjIAHN0T5z7Rre6w9BjnNw9ye4Bt1fVSVX11Pt/98Y396l2I+ZY589toY5ZVZ+uqj0X8vjA0qMgA9zff0jyubXr8K61dumyhdJa+4+WINvoTkjyX8YOASxuCjLA/b0iyf9NkqqaqqpvVtUZSb5dVZtX1fuq6oKquqSqXt/tV1X1oapaU1VfTfK4DZ2kqqarav/u659U1bur6uKqOr+qHt9tf2xVfbY73wVV9cyH+uGq6oCqOrc71993T6RLkidU1Zeq6h+q6s97+59QVRdW1eqq+m+97VdX1X+rqouq6tKq+uVu+zZV9b+6bZdU1Uu67f+uqs7r9v9Mt6bx+nL+ajeSv7KqvlxVO1fVL1fV3/f22b17ut4691/HYb+Z2SX7FvQvO8DSoiAD9FTVI5L8Umvt6t7m/ZL8fmttrySvTXJra+2AzD6u+XVV9aTMrpW8d2YfMf2qJAc9yFM/Ksn5rbVnJDk7yeu67f8jyX/vzveSrOOpe1W1d7fO8bp+bb+Oz3dq93mekdlHQ9/Rvb08s+sVPz3JS7uHdyTJf22t7Z9k38w+XGTf3iFvbq3tl9mR2WO6bW/vfkZPb63tm+Ssmn04ytuSPK/b/8Ikf/hAP4yq2jLJBzP79LxfzezT8N7dWrs8ySO6n3m6vKc+0P5zj9s9yOXKzD7JEGCd/A0a4BftmGRmzra/b61d1X3975Ls25snu12SPTP7OOn/3U3LuL6qznqQ5/1ZkjO7r1cm+bfd189L8tSqWrvfo6tqm9baT9ZuaK2tyWy5nY+9M/vEvwu6770tSbrjf23tsmhV9e0kuyW5NsnhNfskwS2S7JzZvwRc0h3vc73Mv9XL/LJevh9V1Yu67zunO9cjkpy3gZz7JPlKt//mSb7fvXdaZovxsd3vL93A/nPdmOQJXWaA+1GQAX7RHfn5o43X+mnv60ryptbal/s7VNULH+J5724/X3fz3vz8z+fNkvyr1tqdD/SNVbV3ZkeF12WqexLdfNzV+/reJFt0I7XHJDmgK7on5xd/Pnf191/PsSvJV1prvzPPLJVkdWvtwHW8d2qSz1TV5zL7sMN/qKqnr2f/ubbKz0fNAe7HFAuAntbaj5JsXlVzS/JaX07yhu6f9FNVe1XVozI7LeKl3RzlnZM8e4Ei/W2SN619UVXL15F5TWtt+QP8mpmz+5okO1fVAd3xtt3AfNxHZ/YvCLd286JfMI/MX0nye73Mj0lyfpJnVtUe3bZHVdVe6znGmiSPraoDu/23rKqndZ/3u5kt5G/Pz/9i8ID7r8NemX1sNcA6KcgA9/e3Sf71A7x3UpJvJ7moqi5L8pHMjpz+nyT/0L338ax/+sCD8Z+T7N/d7PbtJL/7UA7WWvtZZqckfLCqLs5smX2gvwyktXZxkm8luTzJp5KcM4/TvCvJY6rqsu4cz26t3ZTkyCT/u6ouyezP55c3kPOwJH/WHWNVfnFe96lJjsjsdIv57J8k6Ur+Ha21G+bxOYCHKU/SA5ijqvZL8gettVeOnYWFVVV/kOS21tr/HDsLsHgZQQaYo7V2UZKv10N4UAiL1kySj40dAljcjCADAECPEWQAAOhRkAEAoEdBBgCAHgUZAAB6FGQAAOj5/wFI5fIk3CBlIwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "mean_scores = [np.mean(scores[kind]) for kind in kinds]\n", + "print(list(zip(mean_scores, kinds) ))\n", + "scores_std = [np.std(scores[kind]) for kind in kinds]\n", + "\n", + "plt.figure(figsize=(10, 8))\n", + "positions = np.arange(len(kinds)) * .1 + .1\n", + "plt.barh(positions, mean_scores, align='center', height=.05, xerr=scores_std)\n", + "yticks = [k.replace(' ', '\\n') for k in kinds]\n", + "plt.yticks(positions, yticks)\n", + "plt.gca().grid(True)\n", + "plt.gca().set_axisbelow(True)\n", + "plt.gca().axvline(.8, color='red', linestyle='--')\n", + "plt.xlabel('Classification accuracy\\n(red line = chance level)')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "perfect-surveillance", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 4c844b213adf4aa63ebd7583ce8fb0f6604a0166 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Mon, 19 Jul 2021 20:33:03 +0100 Subject: [PATCH 5/8] modifying cargo.toml --- Cargo.lock | 415 ----------------------------------------------------- Cargo.toml | 6 - 2 files changed, 421 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e59cbc6..2b76384 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,16 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.0.1" @@ -23,39 +12,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "bstr" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cast" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" -dependencies = [ - "rustc_version", -] - [[package]] name = "cfg-if" version = "0.1.10" @@ -68,17 +24,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "clap" -version = "2.33.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "bitflags", - "textwrap", - "unicode-width", -] - [[package]] name = "console" version = "0.14.1" @@ -92,42 +37,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "criterion" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools 0.10.0", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" -dependencies = [ - "cast", - "itertools 0.9.0", -] - [[package]] name = "crossbeam-channel" version = "0.5.1" @@ -173,28 +82,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "ctor" version = "0.1.20" @@ -239,12 +126,6 @@ dependencies = [ "syn", ] -[[package]] -name = "half" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" - [[package]] name = "hermit-abi" version = "0.1.18" @@ -321,39 +202,6 @@ dependencies = [ "syn", ] -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "js-sys" -version = "0.3.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -381,15 +229,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "matrixmultiply" version = "0.2.4" @@ -408,12 +247,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "memchr" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" - [[package]] name = "memoffset" version = "0.6.3" @@ -529,12 +362,6 @@ dependencies = [ "pyo3", ] -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - [[package]] name = "parking_lot" version = "0.11.1" @@ -579,43 +406,6 @@ dependencies = [ "proc-macro-hack", ] -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "plotters" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" - -[[package]] -name = "plotters-svg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" -dependencies = [ - "plotters-backend", -] - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -784,15 +574,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" -dependencies = [ - "byteorder", -] - [[package]] name = "regex-syntax" version = "0.6.25" @@ -803,7 +584,6 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" name = "rust-dtw" version = "0.1.13" dependencies = [ - "criterion", "indicatif", "ndarray 0.14.0", "ndarray-rand", @@ -813,92 +593,12 @@ dependencies = [ "rand", ] -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" - -[[package]] -name = "serde_cbor" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "smallvec" version = "1.6.1" @@ -926,37 +626,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unicode-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -969,87 +638,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" -[[package]] -name = "wasm-bindgen" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" - -[[package]] -name = "web-sys" -version = "0.3.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1066,15 +660,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 0d1d717..78d7910 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,9 +28,3 @@ indicatif = { version = "0.16.2", features = ["rayon"] } version = "0.13.2" features = ["extension-module"] -[dev-dependencies] -criterion = "0.3.4" - -[[bench]] -name = "my_benchmark" -harness = false From f6409b6d8eb93f741018dcd3f0a57cc3a63aac76 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Mon, 19 Jul 2021 21:56:54 +0100 Subject: [PATCH 6/8] Finalizing example --- .../classification/ABIDE_classification.ipynb | 346 ++++-------------- 1 file changed, 73 insertions(+), 273 deletions(-) diff --git a/examples/classification/ABIDE_classification.ipynb b/examples/classification/ABIDE_classification.ipynb index 160f630..cb0275f 100644 --- a/examples/classification/ABIDE_classification.ipynb +++ b/examples/classification/ABIDE_classification.ipynb @@ -2,12 +2,21 @@ "cells": [ { "cell_type": "code", - "execution_count": 3, + "execution_count": 38, "id": "spare-number", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/numpy/lib/npyio.py:2349: VisibleDeprecationWarning: Reading unicode strings without specifying the encoding argument is deprecated. Set the encoding, use None for the system default.\n", + " output = genfromtxt(fname, **kwargs)\n" + ] + } + ], "source": [ "#Modified version of the following script from nilearn: \n", "#https://nilearn.github.io/auto_examples/03_connectivity/plot_group_level_connectivity.html\n", @@ -19,7 +28,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 39, "id": "frank-glenn", "metadata": { "scrolled": false @@ -31,7 +40,7 @@ "dict_keys(['description', 'phenotypic', 'func_preproc'])" ] }, - "execution_count": 11, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -42,19 +51,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 40, "id": "difficult-multiple", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/fleetwood/miniconda3/lib/python3.6/site-packages/numpy/lib/npyio.py:2349: VisibleDeprecationWarning: Reading unicode strings without specifying the encoding argument is deprecated. Set the encoding, use None for the system default.\n", - " output = genfromtxt(fname, **kwargs)\n" - ] - } - ], + "outputs": [], "source": [ "from nilearn import input_data\n", "\n", @@ -66,14 +66,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 41, "id": "cardiac-canadian", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ff312cd1ea494c188b7c4b2a694c82ab", + "model_id": "a60c254988fb400fa8c08d47ff36a3ca", "version_major": 2, "version_minor": 0 }, @@ -105,243 +105,57 @@ }, { "cell_type": "code", - "execution_count": 38, - "id": "varied-federation", + "execution_count": 42, + "id": "substantial-meditation", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(196, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(206, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(78, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(176, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(146, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n", - "(296, 39)\n" - ] - } - ], + "outputs": [], "source": [ - "for elem in pooled_subjects:\n", - " print(elem.shape)" + "n_regions = pooled_subjects[0].shape[1]" ] }, { "cell_type": "code", "execution_count": 43, - "id": "occupied-photographer", + "id": "cardiovascular-equivalent", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "200\n" - ] - } - ], + "outputs": [], "source": [ - "print(len(groups))" + "def sym_matrix_to_vec(symmetric):\n", + " tril_mask = np.tril(np.ones(symmetric.shape[-2:]), k=-1).astype(np.bool)\n", + " return symmetric[..., tril_mask]" ] }, { "cell_type": "code", "execution_count": 44, + "id": "natural-editing", + "metadata": {}, + "outputs": [], + "source": [ + "def compute_dtw(subjects, n_regions):\n", + " dtw_output = []\n", + " for subj in subjects:\n", + " dtw_output.append(\n", + " rust_dtw.dtw_connectome(\n", + " connectome=subj,\n", + " window=100, \n", + " distance_mode=\"euclidean\")\n", + " )\n", + " connectomes = []\n", + " #Post processing them as per paper recommendations\n", + " for vec in dtw_output:\n", + " sym = np.zeros((n_regions, n_regions))\n", + " sym[i_lower] = vec\n", + " sym += sym.T\n", + " sym *= -1\n", + " StandardScaler().fit_transform(sym)\n", + " connectomes.append(sym_matrix_to_vec(sym))\n", + " return connectomes" + ] + }, + { + "cell_type": "code", + "execution_count": 45, "id": "structured-defensive", "metadata": { "scrolled": false @@ -358,10 +172,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/fleetwood/miniconda3/lib/python3.6/site-packages/sklearn/svm/_base.py:983: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.\n", - " \"the number of iterations.\", ConvergenceWarning)\n", - "/home/fleetwood/miniconda3/lib/python3.6/site-packages/sklearn/svm/_base.py:983: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.\n", - " \"the number of iterations.\", ConvergenceWarning)\n" + "/home/fleetwood/miniconda3/lib/python3.6/site-packages/numpy/core/_asarray.py:83: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray\n", + " return array(a, dtype, copy=False, order=order)\n" ] }, { @@ -377,10 +189,13 @@ "source": [ "from sklearn.svm import LinearSVC\n", "from sklearn.model_selection import StratifiedShuffleSplit\n", + "from sklearn.preprocessing import StandardScaler\n", "from sklearn.metrics import accuracy_score\n", "from nilearn.connectome import ConnectivityMeasure\n", + "import matplotlib.pyplot as plt\n", "import rust_dtw\n", "import numpy as np\n", + "import copy\n", "\n", "kinds = ['dtw', 'correlation', 'partial correlation', 'tangent']\n", "# kinds = ['correlation']\n", @@ -393,25 +208,9 @@ " print('PROCESSING: ', kind)\n", " scores[kind] = []\n", " for train, test in cv.split(pooled_subjects, classes):\n", - " if kind == 'dtw':\n", - "# Having to do it this way because there are different time series configurations in the provided\n", - "# data. Otherwise rust_dtw.dtw_connectomes would be easier\n", - " connectomes = []\n", - " for subj in pooled_subjects[train]:\n", - " connectomes.append(\n", - " rust_dtw.dtw_connectome(\n", - " connectome=subj,\n", - " window=100, \n", - " distance_mode=\"euclidean\")\n", - " )\n", - " test_connectomes = []\n", - " for subj in pooled_subjects[test]:\n", - " test_connectomes.append(\n", - " rust_dtw.dtw_connectome(\n", - " connectome=subj,\n", - " window=100, \n", - " distance_mode=\"euclidean\")\n", - " )\n", + " if kind == 'dtw': \n", + " connectomes = compute_dtw(pooled_subjects[train], n_regions)\n", + " test_connectomes = compute_dtw(pooled_subjects[test], n_regions)\n", " else:\n", " connectivity = ConnectivityMeasure(kind=kind, vectorize=True)\n", " connectomes = connectivity.fit_transform(pooled_subjects[train])\n", @@ -427,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 52, "id": "optical-satisfaction", "metadata": {}, "outputs": [ @@ -440,33 +239,34 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABBIAAAKqCAYAAACHEX3kAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAABdcElEQVR4nO3de9zX8/0/8EdHpKNTTnPuulBSskiJ5Tg0aeaUGG1FG5vZHMbX135mczZkTkOEmK2IxczaLCwp5BQidJCcKik6fn5/uF3X1+WqvKsrV7jfbze327xfr8/r/Xy/e62bz+Pzer/edUqlUikAAAAABdSt7QIAAACArw5BAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAqrX9sF8OXq0aNHpkyZkkaNGmXzzTev7XIAAABYzbz55puZO3duNt1009xzzz3V2gUJ3zBTpkzJ7NmzM3v27EyfPr22ywEAAGA1NWXKlCUeFyR8wzRq1CizZ89OkyZNst1229V2ObBKzZ49O0nSpEmTWq4EVj3znW8S851vEvOd2jB+/PjMnj07jRo1WmK7IOEbZvPNN8/06dOz3XbbZdCgQbVdDqxSY8eOTZJ06NChliuBVc9855vEfOebxHynNvTu3TujR49e6uPwNlsEAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUVr+2C6B2jJr4frY442+1XQZ8Oe421/kGMd/5JjHfV4k3LjiwtksAVnNWJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKW22DhOHDh+fhhx+u7TJq3bhx4zJw4MDaLgMAAACSrMZBwpVXXilISPLXv/41t956a22XAQAAAElW0yBh1qxZeeONN2q7jNXCuHHjarsEAAAAqLTaBQlnnHFGOnbsmFKplKFDh6a8vDy9e/dOknz88ccZMGBAunfvnh133DFt2rRJt27dcs455+S9996rMs6UKVNSXl6eww47LPPnz8/ll1+evfbaK23atEmXLl1y9tln58MPP6x2/vvvvz89e/bMjjvumE6dOuW0007Lu+++mwsvvDDl5eUZPHhwlf6ffPJJrr766nTv3j1t27ZN+/bt07NnzwwcODALFy6s0veqq66qHGPChAnp379/dt1117Rp0yYHHXRQ7r777sq+Q4YMSXl5eV566aVMnTo15eXlKS8vr6nbDAAAACukfm0X8HkHHHBA1lhjjdx5551p06ZNDjjggGy00UZZvHhxfvzjH+fJJ59M27Zt06dPn5RKpfznP//JXXfdlccffzz33HNPGjduXG3Mk046KW+99VYOOeSQzJ07N/fff3/uvvvuvP/++7nmmmsq+/3lL3/JWWedlTXXXDM9evRIy5Yt85///CdHHnlkdtlll2rjfvLJJzn66KPz3HPPZccdd8xxxx2X+fPn59///nd+//vf5/HHH8+1116bunWr5jWTJk3KZZddlq5du+bYY4/NG2+8kWHDhuXss89O8+bNs88++2SHHXbIaaedlosuuijNmjVLv379av5mAwAAwHJa7YKErl27VgYJrVq1Sp8+fZIko0aNypNPPpntttsugwcPTv36n5Z+0kkn5Qc/+EGef/753HvvvenVq1eV8Z5//vl06tQpf/3rX9OwYcMkybHHHptu3brlX//6V2bOnJnmzZtnwYIFufTSS5Mk1157bTp16pQk6d+/f04//fTce++91Wr94x//mOeeey6HHXZY/t//+3+pU6dOkuSUU07Jj370ozzyyCMZOnRovv/971f53C233JLf/e536dGjR+WxbbbZJpdcckmGDh2affbZJ61atUqrVq1y0UUXpXHjxpX3YUmGDBmSoUOHFrq/48ePL9QPAFi9zXz09sx6bPAXd4TlVOfC2q6Ar7Mf//jHfiT9Cpg9e/Yy21e7IGFpWrVqlZtvvjnNmjWrDBGSpG7duvnOd76T559/Pi+//HK1zy1a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27dfan0vvfRSjjzyyCxYsCAHHnhgttxyy7z33nu59957c+6552by5Mk57bTTVtn9AQAAgBX1tQwShg0blgsvvDA9evSoPLbbbrvl5z//eS6++OLsvffemTx5coYNG5b1118/d999d9Zee+3KvieddFIeeuihDBo0qNoX+lmzZqVu3bq5+uqrK4+1bt0606dPz2OPPZbdd989PXv2XGZ9N998c+bOnZvTTjstffr0qTx+6KGHpkePHrn11ltz4oknpkmTJit5JwAAAKBmfS2DhM0226xKiJAk+++/f9Zff/288cYbmTx5cpo3b55bbrkl9evXrxIiJEm3bt3y0EMP5eWXX6429oIFC74wKPgiffr0yX777ZeddtqpyvFtt902G2+8caZOnZrXXnst7dq1W6nzAAAAQE37WgYJO+64Y7VjderUyZZbbpl33303EydOzB577JFdd901SVIqlTJr1qzMmTOnyv4E8+fPX+L422+//UrVV1ZWlrKysspzzJgxIwsWLEiSNG3aNFOnTs28efNW6hwAAACwKnwtg4R11113icebNm2aJPnwww+TJE8++WQGDBiQsWPHVn6RL6JZs2YrVd8nn3ySAQMG5L777svbb7+9UmMBAADAl+lrGSTUrbvkl1EsXrw4SbLGGmtk1KhROf7447No0aIcdNBB2XXXXdO0adPUq1cvL774YpU9ED6vXr16K1Vfv379MmrUqHzrW9/KySefnM033zxrrrlmkuTiiy/OG2+8sVLjAwAAwKrytQwSZsyYscTjs2fPTvLpioVrrrkmixYtys9+9rP079+/Sr+lPdJQE8aNG5dRo0Zl/fXXz5///Oess846VdovvfTSVXZuAAAAWFlL/un+K+7ZZ5+tdmzx4sWZOHFikmSTTTbJlClTkny6seLnjRw5cpXVVnHeHXfcsVqIMHnyZKsRAAAAWK19LYOE1157LQ8++GCVY8OHD8/777+f8vLybLjhhmnZsmWSZMKECVX6DRs2LI899liST1/1WNQaa6yRZOmrISpUnHfixImVj1okyQcffJDTTz+9cn+Hin0cAAAAYHXytXy0Yf/998/ZZ5+dBx54IK1atcr06dMzdOjQ1K1bN7/85S+TJIccckhGjRqVc889N88//3yaNm2ap556KuPHj891112Xww8/PK+88kp+97vfZf/996/2qsbP22abbZIkN9xwQ6ZOnZqWLVumX79+1frtuOOO2WqrrTJx4sQce+yx6dSpUz744IMMHz48Bx98cHbYYYcMHDgwAwYMyOuvv56+ffvW/A0CAACAFfS1XJHwrW99K7fcckvmzJmTgQMHZtiwYWndunWuu+66dO3aNUnSo0ePnHvuudlwww1z55135s4778w666yTu+66KzvssEN+8YtfpFmzZhkyZEgmTZr0hefcc88984Mf/CDz58/PkCFD8uabby6xX4MGDXLDDTdk3333zWuvvZYbbrghY8eOzc9//vOcfvrpOfbYY9O2bdtMnDgx999/f43eFwAAAFhZdUqlUqm2i6gpV111VQYMGJAf//jHlSsPqKp3794ZPXp0Fq+3dRbs/pPaLgcA4EvxxgUH1nYJsELGjh2bJOnQoUMtV8I3ScX3xo4dO2bQoEHV2r+WjzZ80wwZMiRDhw4t1Hf8+PGruBoAWH3NfPT2zHpscG2XQS2oc2FtV0Bt+vGPf7zEx46/SioCBfgyVLzxcGkECV8DU6dOzejRo2u7DAAAAL4BBAlfA5tsskk6duxYqO/48eO/MF0CAICvk4033vgr+2iARxuoDU2aNFlmuyDha6Bnz57p2bNnob4Vz7oAwDdR8y690rxLr9oug1pgjwSAmvO1ChJOOumknHTSSbVdBgAAAHxtfS1f/wgAAACsGoIEAAAAoLBvTJDQu3fvlJeXZ8qUKTU+9lVXXZXy8vIMGTKkxscGAACA1cnXao+EL8Odd96ZLbfcMrvsskvlsc6dO6dRo0bZYYcdarEyAAAAWPW+MSsSasKiRYty4YUXVnvrwU477ZQ+ffqkVatWtVQZAAAAfDkECcvhlVdeydy5c2u7DAAAAKg1hYOEhQsX5uabb87BBx+cdu3apX379vnhD3+YMWPGVOk3f/783HDDDTnkkEPSvn37tG3bNvvtt18uuOCCfPDBB1X6DhkyJOXl5bnkkkvyj3/8I/vuu2/l4wFTpkxJeXl5DjvssLz66qs5/PDD07Zt2yrnmzZtWs4555x069Ytbdq0yS677JLjjjsuI0aMKHwDnnrqqfTv3z+dO3dO69ats9NOO+Woo47K8OHDq/Tr3bt3evTokSQZMGBAysvLc8YZZyRZ+h4Js2fPzuWXX54DDjggO+64Y9q1a5fu3btnwIABmTNnTpW+FWMMHjw4EyZMSP/+/bPrrrumTZs2Oeigg3L33XcXviYAAABYVQrtkbB48eKccMIJGTlyZHbZZZf07ds3M2fOzL333ptevXrlsssuy4EHHpgFCxakT58+GT16dMrKynLYYYdlzTXXzLPPPpubb745//jHP3LXXXdlvfXWqzL+O++8k//5n/9Jjx490rhx42rnP/XUU1NWVpZu3bqlZcuWSZLXXnstvXr1ysyZM7P33nunZ8+eee+99zJ8+PCceOKJOfXUU9O3b99lXtfIkSNzwgknpGHDhunevXs23njjvPXWW7nnnntyyimnZMaMGenVq1eS5Mgjj8x6662X4cOHp3PnzuncufMyH2WYPXt2jjjiiLz66qtp165devfunVKplCeffDJXXXVVRowYkTvuuCNrrrlmlc9NmjQpl112Wbp27Zpjjz02b7zxRoYNG5azzz47zZs3zz777FPkjwwAAABWiUJBwh133JGRI0emR48eufDCCyuP9+rVK927d88555yTvfbaK4MHD87o0aPTqVOn/OlPf0r9+v83/HnnnZfbbrstl19+ec4///wq4z/44IO59NJLl/gl+aWXXsphhx2Ws88+u8rxs846KzNmzMjFF1+c733ve5XH+/fvn+9973u54oorsu+++2aLLbZY6nVdd911WbhwYS699NLsv//+lcf33HPPnHjiibn66qtz1FFHpU6dOjnggAPyySefZPjw4Wnfvn369OmzzHt2xRVX5NVXX80hhxySCy64oPJ4qVRK//79M2LEiNx0003p379/lc/dcsst+d3vfle5+iFJttlmm1xyySUZOnSoIAEAAIBaVejRhopl9Z//8rz55pvntNNOy/HHH59Zs2blnnvuSZL89Kc/rRIiJEm/fv2SJMOHD8+iRYuqtDVq1CjdunVb4rnnzZuXQw89tMqxCRMm5Omnn07r1q2rhAhJssEGG+SYY47JwoULc//99y/zuk477bRcffXV1c69xx57pH79+nn//ffz3nvvLXOMJSmVShk2bFiS5OSTT67SVqdOncp7saT6ysrKqoQISdKlS5ckyRtvvLHctQAAAEBN+sIVCfPnz88rr7ySBg0aZJtttqnWfvTRR1f2mzBhQurVq5e2bdtW67fBBhtko402yrRp0zJ58uQqKwXKy8tTr169JZ6/Xr16KS8vr3LsmWeeSZJsttlmmTJlSrXPbLzxxkmSF154YZnX9tk6P/7448ycObMy5GjSpElmzJiRefPmLXOMJZk0aVJmzZqVDTfcsLKWz9p+++1Tr169vP7665k3b17WWGONyrbWrVtX61/xuMcnn3yy3LUAAABATfrCIGHGjBlZvHhxmjVrlrp1l76AoeJLePPmzdOwYcMl9llnnXUybdq0zJgxo0qQ0KxZs6WO27Rp09SpU6fKsYpNGx944IE88MADS/3s+++/v9S25NNr+8Mf/pCHHnqo2kaQK6NirHXXXXeJ7Q0bNkyTJk0yc+bMzJo1KxtssEFlW4sWLar1//z1AwAAQG35wiCh4kvs/PnzC/UrlUpL7bN48eIkqRZILG01wtLaKs6155575gc/+MFSP9ukSZOltn3yySfp3bt3JkyYkPLy8vTp0ycbbbRR5eqAM888Mx9++OFSP78sK3MvAAAAYHX2hUFC8+bNU79+/cyZMyfz589f6mqDZs2apX79+vnoo4+W2q/il/p11llnpYqueOvDWmutlb333nuFxhgxYkQmTJiQsrKy/PnPf67y9oTFixdn4cKFK1xfxUqEpa2ImD9/fubMmZP69eunadOmK3weAAAA+LJ94c/hDRs2TFlZWZJk1KhR1dqvv/769O/fPxMnTkx5eXkWLVpUuYfBZ7311luZPn16mjdvnk033XSlit5xxx2TJGPGjMmCBQuqtX/44YeZMWPGMseo2FuhU6dO1V7BOGbMmMydO3eF69t0003TvHnzTJ8+PVOnTq3W/uyzz2bRokUpLy9fajADAAAAq6NC6+or3iIwcODAKm9ceOutt3L99ddn1KhR2WyzzSrfrnDNNddU+0X/6quvTpL07NlzpZ/533rrrdO+ffu8++67ueWWW6q0LVy4MGeddVZ22223/Pe//13qGBX7Erz66qtVjk+ePDnnn39+mjdvniRVHm+oeOzhi0KKOnXqVN6LAQMGVGlbtGhRrrnmmiTJ97///WWOAwAAAKubL3y0IUmOOuqoPPzww3nsscdy+OGHZ88998zs2bMzbNiwfPTRR7n00kvTqFGjHH744ZX9Dj300HTu3Dl169bN2LFjM3bs2Gy77bb56U9/WiOFn3feeendu3cuvvjijB49Ou3bt89HH32UESNGZOLEidlnn32yyy67LPXze+65Z1q0aJHHHnss/fv3zw477JBp06blb3/7W0455ZSMGjUq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m2++Of/4xz9y1113Zb311qsy/jvvvJP/+Z//SY8ePdK4ceNq5z/11FNTVlaWbt26pWXLlkmS1157Lb169crMmTOz9957p2fPnnnvvfcyfPjwnHjiiTn11FPTt2/fZV7XyJEjc8IJJ6Rhw4bp3r17Nt5447z11lu55557csopp2TGjBnp1atXkuTII4/Meuutl+HDh6dz587p3LnzMh9lmD17do444oi8+uqradeuXXr37p1SqZQnn3wyV111VUaMGJE77rgja665ZpXPTZo0KZdddlm6du2aY489Nm+88UaGDRuWs88+O82bN88+++xT5I8MAAAAVolCQcIdd9yRkSNHpkePHrnwwgsrj/fq1Svdu3fPOeeck7322iuDBw/O6NGj06lTp/zpT39K/fr/N/x5552X2267LZdffnnOP//8KuM/+OCDufTSS5f4Jfmll17KYYcdlrPPPrvK8bPOOiszZszIxRdfnO9973uVx/v375/vfe97ueKKK7Lvvvtmiy22WOp1XXfddVm4cGEuvfTS7L///pXH99xzz5x44om5+uqrc9RRR6VOnTo54IAD8sknn2T48OFp3759+vTps8x7dsUVV+TVV1/NIYcckgsuuKDyeKlUSv/+/TNixIjcdNNN6d+/f5XP3XLLLfnd735XufohSbbZZptccsklGTp06BLv0ZAhQzJ06NBl1lNh/PjxhfoBQBEzH709sx4bXNtlwGqhzoVf3Ae+SX784x+nX79+tV0GK2D27NnLbC/0aEPFsvrPf3nefPPNc9ppp+X444/PrFmzcs899yRJfvrTn1YJEZJUTqDhw4dn0aJFVdoaNWqUbt26LfHc8+bNy6GHHlrl2IQJE/L000+ndevWVUKEJNlggw1yzDHHZOHChbn//vuXeV2nnXZarr766mrn3mOPPVK/fv28//77ee+995Y5xpKUSqUMGzYsSXLyySdXaatTp07lvVhSfWVlZVVChCTp0qVLkuSNN95Y4vmmTp2a0aNHF/rniyYEAAAALMsXrkiYP39+XnnllTRo0CDbbLNNtfajjz66st+ECRNSr169tG3btlq/DTbYIBtttFGmTZuWyZMnV1kpUF5ennr16i3x/PXq1Ut5eXmVY88880ySZLPNNsuUKVOqfWbjjTdOkrzwwgvLvLbP1vnxxx9n5syZlSFHkyZNMmPGjMybN2+ZYyzJpEmTMmvWrGy44YaVtXzW9ttvn3r16uX111/PvHnzssYaa1S2tW7dulr/isc9PvnkkyWeb5NNNknHjh0L1TZ+/HhhAgAAsMptvPHG6dChQ22XwQpo0qTJMtu/MEiYMWNGFi9enGbNmqVu3aUvYKj4Et68efM0bNhwiX3WWWedTJs2LTNmzKgSJDRr1myp4zZt2jR16tSpcqxi08YHHnggDzzwwFI/+/777y+1Lfn02v7whz/koYceqrYR5MqoGGvdddddYnvDhg3TpEmTzJw5M7NmzcoGG2xQ2daiRYtq/T9//Z/Xs2fP9OzZs1BtvXv3rvb6SgBYUc279ErzLr1quwxYLbxxwYG1XQJfQ2PHjk0SX8hZrXxhkFDxJXb+/PmF+pVKpaX2Wbx4cZJUCySWthphaW0V59pzzz3zgx/8YKmfXVaK8sknn6R3796ZMGFCysvL06dPn2y00UaVqwPOPPPMfPjhh0v9/LKszL0AAACA1dkXBgnNmzdP/fr1M2fOnMyfP3+pqw2aNWuW+vXr56OPPlpqv4pf6tdZZ52VKrrirQ9rrbVW9t577xUaY8SIEZkwYULKysry5z//ucrbExYvXpyFCxeucH0VKxGWtiJi/vz5mTNnTurXr5+mTZuu8HkAAADgy/aFP4c3bNgwZWVlSZJRo0ZVa7/++uvTv3//TJw4MeXl5Vm0aFHlHgaf9dZbb2X69Olp3rx5Nt1005Uqescdd0ySjBkzJgsWLKjW/uGHH2bGjBnLHKNib4VOnTpVewXjmDFjMnfu3BWub9NNN03z5s0zffr0TJ06tVr7s88+m0WLFqW8vHypwQwAAACsjgqtq694i8DAgQOrvHHhrbfeyvXXX59Ro0Zls802q3y7wjXXXFPtF/2rr746yafP83/RM/9fZOutt0779u3z7rvv5pZbbqnStnDhwpx11lnZbbfd8t///nepY1TsS/Dqq69WOT558uScf/75ad68eZJUebyh4rGHLwop6tSpU3kvBgwYUKVt0aJFueaaa5Ik3//+95c5DgAAAKxuvvDRhiQ56qij8vDDD+exxx7L4Ycfnj333DOzZ8/OsGHD8tFHH+XSSy9No0aNcvjhh1f2O/TQQ9O5c+fUrVs3Y8eOzdixY7Ptttvmpz/9aY0Uft5556V37965+OKLM3r06LRv3z4fffRRRowYkYkTJ2afffbJLrvsstTP77nnnmnRokUee+yx9O/fPzvssEOmTZuWv/3tbznllFMyatSo/OMf/8jvfve7HHTQQTniiCOy9dZbJ0mGDBmShQsXZu21187pp5++xPH79++fkSNHZsiQIZk0aVJ23nnnzJ8/P//9738zfvz4dOnSJUcccUSN3AsAAAD4shQKEho0aJAbb7wxN910U+6///7ccMMNqVu3btq2bZu+ffumc+fOST7dGPHaa6/Nrbfemvvuuy+33XZbSqVSNttss5x00kk57rjjsvbaa9dI4a1atcqQIUNy3XXXZeTIkXn88cfToEGDbLXVVjnrrLNy5JFHLnMjw+bNm2fgwIG56KKLMnbs2DzxxBNp1apVLrjgguyzzz7Zeeed8/rrr2fcuHFp3LhxjjjiiGy77bbp379/7rjjjtxzzz3L3Dl17bXXzh133JEbbrghDz30UG666abUr18/W265Zc4888z06tVrmZtMAgAAwOqoTmlZrxbga6fi9Y+L19s6C3b/SW2XAwDwteH1j6wKXv9Ibaj43tixY8cMGjSoWrt3DwIAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQWP3aLoDasetW62bQBQfWdhmwSo0dOzZJ0qFDh1quBFY9851vEvMdoHZZkQAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoLD6tV0AtWPUxPezxRl/q+0y4Mtxt7nON4j5zjeJ+b5KvHHBgbVdArCasyIBAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEFCDXviiSdSXl6e3r1713YpAAAAUOMECV+CcePGZeDAgbVdBgAAAKw0QcKX4K9//WtuvfXW2i4DAAAAVpog4Uswbty42i4BAAAAaoQgYQW98cYb+elPf5pvf/vbadeuXXr27Jnhw4dX6TNkyJCUl5fnpZdeytSpU1NeXp7y8vJcfvnlKS8vzz333FNt3AMPPDDl5eUZMGBAtbZ+/fqlvLw8r7zyyqq6LAAAAFgmQcIKePfdd9OrV6/84x//SLt27dK3b9+0bt06v/nNb6qEAzvssENOO+20JEmzZs1y2mmn5bTTTstuu+2WJHnyySerjPvee+/l1VdfTYMGDaq1LVq0KGPGjEnLli1TVla2ai8QAAAAlqJ+bRfwVXTjjTfmvffey6GHHprzzz+/8vgJJ5yQgw8+uPLfW7VqlVatWuWiiy5K48aN06dPnyTJ/Pnz06hRo4wZM6bKuE888USSZL/99svDDz+cBQsWpEGDBkmSF154IR999FH23XffavUMGTIkQ4cOLVT7+PHjl+9iAWA1NfPR2zPrscG1XQZ87dS5sLYrgK+vH//4x+nXr19tl/GFZs+evcx2QcIK+Oc//5kkOfbYY6sc32STTdKzZ8/ccssty/x8w4YN8+1vfzuPPPJI3n333ay//vpJPg0SmjdvngMPPDD3339/nnvuuey0006VbUmy++67Vxtv6tSpGT169EpfFwAAAHwRQcJy+uSTTzJ58uQ0aNAg22yzTbX2HXfcsdA4u+22Wx555JE8+eSTOeCAA5Iko0aNSvv27bPzzjunbt26efLJJyuDhNGjR6du3brp1KlTtbE22WSTdOzYsdB5x48f/4XpEgAAADVv4403TocOHWq7jC/UpEmTZbYLEpbTrFmzUiqVsvbaa6du3epbTDRv3rzQOJ07d06SjBkzJgcccEDefvvtvPnmmzn88MPTtGnTlJWV5cknn0y/fv2ycOHCjB07Nm3atEmLFi2qjdWzZ8/07Nmz0Hl79+5t9QIAXwvNu/RK8y69arsM+Np544IDa7sEPmPs2LFJ8pX48sk3h80WV1CdOnWWeHzx4sWFPt+qVatssMEGlZsqjho1KkkqVxbsvPPOeeqpp7Jo0aK88MILmTNnTrp06VIDlQMAAMCKEyQsp4olHh999FFKpVK19vfff7/wWJ07d86ECRMya9asPPHEE2nSpEm23377JJ8GCXPmzMmLL75YuT+CIAEAAIDaJkhYTo0aNcqGG26YBQsW5PXXX6/W/swzzxQea7fddkupVMqYMWMyatSodOjQIfXq1UvyaZCQfPqKyDFjxqRJkyaF918AAACAVUWQsAL22GOPJMntt99e5fjkyZMzbNiwav0bNmyYWbNmZdGiRVWOd+7cOXXq1Mnw4cPz1ltvVdkwcf31188WW2yR0aNHZ9y4cenUqVPq17elBQAAALXLN9MV8OMf/zjDhw/PbbfdlmnTpmWHHXbIW2+9lYceeig9evSoFjC0atUqL7zwQvr27ZvNNtssRx11VFq1apV111035eXl+fvf/54k1d680KFDhwwbNiwLFizwWAMAAACrBSsSVsC3vvWt3Hbbbdljjz3yxBNP5Nprr81zzz2XM888M0cddVS1/meffXa22mqrPPHEE3n44YezcOHCyrbddtstCxYsqLI/QoVvf/vbWbBgQRL7IwAAALB6qFNa0o6BfG1VvP5x8XpbZ8HuP6ntcgAAWM14/ePqxesfqQ0V3xs7duyYQYMGVWu3IgEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGH1a7sAaseuW62bQRccWNtlwCo1duzYJEmHDh1quRJY9cx3vknMd4DaZUUCAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAAACAwgQJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAKEyQAAAAAhQkSAAAAgMIECQAAAEBhggQAAACgMEECAAAAUFj92i6AL9ebb76ZJBk/fnx69+5dy9XAqjV79uwkSZMmTWq5Elj1zHe+Scx3vknMd2rD+PHjk/zf98fPEyR8w8yaNSvJp38hjR49uparAQAAYHU1d+7cJR4XJHzD1K376dMsDRo0SPv27Wu5Gli1xo8fn9mzZ6dJkybZbrvtarscWKXMd75JzHe+Scx3asObb76ZuXPnZtNNN11iuyDhG6ZNmzYZPXp02rdvn0GDBtV2ObBK9e7dO6NHj852221nvvO1Z77zTWK+801ivrM6stkiAAAAUJggAQAAAChMkAAAAAAUJkgAAAAAChMkAAAAAIUJEgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFBY/dougC/XIYccko4dO2aTTTap7VJglTPf+SYx3/kmMd/5JjHfWR3VKZVKpdouAgAAAPhq8GgDAAAAUJggAQAAAChMkAAAAAAUZrPFr4kHH3wwt99+e1588cXMnz8/m2++eQ488MAcd9xxWXPNNQuN8cILL+S6667LmDFj8uGHH2b99dfP7rvvnp/85Cdp2bLlKr4CKK4m5vujjz6aW265Jc8++2w++uijNGvWLO3bt0+fPn2y0047reIrgGJqYq5/3sknn5y///3v6dixYwYNGlTDFcOKq4n5vnDhwtx6660ZOnRo3nzzzay11lopKyvLcccdl27duq3iK4DiVna+l0ql3HPPPRkyZEheeumlzJ07N02bNs0OO+yQww8/PHvttdeXcBV8k9ls8WvgqquuyoABA7LRRhvlu9/9bho3bpzHH388Y8aMSceOHXPzzTenfv1lZ0YjR45M//79U69evXzve9/LxhtvnAkTJmT48OFZb731cuedd9opltVCTcz3P/3pT7n44ovTqFGjHHDAAdloo43y8ssv5x//+Efq1KmTq666KnvvvfeXdEWwZDUx1z/vnnvuyemnn54kggRWKzUx3xcsWJATTjghjz76aDp37pydd94577//fu67777MmjUr5513Xg477LAv6Ypg6Wpivp9++um55557st5662X//ffPBhtskGnTpmXYsGGZM2dOfvrTn+akk076kq6Ib6QSX2njx48vbbvttqVu3bqVZs6cWaXtV7/6VamsrKx04403LnOMefPmlbp06VJq3bp16dlnn63S9uc//7lUVlZW6tevX43XDsurJub7a6+9Vtpuu+1KO++8c2nixIlV2v7yl7+UysrKSnvttVeN1w7Loybm+ue99dZbpQ4dOpQOOeSQUllZWenoo4+uyZJhhdXUfL/mmmtKZWVlpRtuuKHK8YkTJ5Z22mmn0lFHHVVatGhRjdYOy6sm5vvTTz9dKisrK3Xu3Ln0wQcfVGl77bXXSq1bty5tv/32pffff7/G64cK9kj4irvrrruyePHi9OnTJ82aNavSVpFCDh48eJlj/POf/8w777yTvffeOzvssEOVtu9///vZZJNN8u9//ztvvfVWzRYPy6km5vtTTz2Vxo0b5+CDD86WW25Zpa1Hjx5ZY401Mnny5Lzzzjs1Wzwsh5qY659VKpVyxhlnZNGiRZUrEmB1URPzfeHChRk4cGBatWqVPn36VGnbcsstM3bs2Nx+++2pW9d/+lK7amK+v/7660mSDh06pEWLFlXattpqq2y55ZZZuHBhpkyZUoOVQ1X+Nv2KGzVqVJKkc+fO1dq+9a1vZZNNNsmkSZOWGQIsa4y6deumY8eOKZVKGT16dA1VDSumJub7oYcemtGjR+fss8+u1lavXr2stdZaSZLFixfXUNWw/Gpirn/WLbfcklGjRuX000/3mBqrnZqY72PHjs2MGTOy3377pU6dOkmSGTNmZMaMGaumaFhBNTHfy8rKknwaKJQ+95T6vHnz8s4772SNNdbIFltsUXOFw+cIEr7CFixYkDfffDP16tXLpptuusQ+m2++eZJkwoQJSx3n1VdfTZJsttlmKzwGrGo1Nd+X5ZlnnsnMmTOzxRZbZMMNN1zhWmFl1PRcf+2113LZZZdl9913zxFHHFGjtcLKqqn5Pn78+CTJNttsk0GDBmXPPffMrrvuml133TXdunXLn//855ovHpZTTc331q1b56ijjsrLL7+cU045JU8//XQmTZqUMWPG5Oc//3lmzpyZX/ziF2natOkquQ5IvLXhK+2jjz7KokWL0qRJk9SrV2+JfSqWTH344YdLHaeibWl/2RQZA1a1mprvyxr/f/7nf5Ikp5566ooXCiupJuf6ggUL8qtf/Sprrrlmzj///BqvFVZWTc33adOmJfl0SfiECRPSq1evbLnllnnttddy00035X/+53/y3nvvpX///jV/EVBQTf79/r//+79p3bp1zj///DzwwAOVx9dbb71cffXVNo1mlRMkfIV98sknSZIGDRostU/Dhg2r9F2Sjz/+eJnjVIxR0Q9qQ03N9yV5//33c8IJJ+SVV17Jj370o+y7774rXiispJqc61dffXVeeOGFXHrppV7jy2qppub7nDlzkiQvvfRShgwZUuXX3j333DOHHXZY/vjHP+b73/++/y9Qa2ry7/fbbrstv//977P55pvnqKOOyrrrrptp06blrrvuyimnnJLzzjsvPXr0qLHa4fMECV9hFe+YXbBgwVL7zJs3r0rfJal4Jnxp41SMUdEPakNNzffPe/XVV9OvX79MmTIlffv2zS9+8YuVKxRWUk3N9XHjxuX666/P/vvvn4MOOqhmi4QaUlPzveLX3UMOOaTakvG2bdumc+fOefTRR/Of//wnP/jBD1a2bFghNTXfx44dm9/+9rcpKyvL3XffnTXWWKOy7fDDD88BBxyQs88+OzvuuGO1jaWhptgj4SusSZMmqV+/fubMmZP58+cvsU/FJkOf39H1s5o3b54kmTlz5gqPAataTc33z/rPf/6Tww8/PNOnT895552XU089tXKTLqgtNTHXP/7445x22mnZYIMN8pvf/GaV1Qorq6b/W2bdddddYnurVq2S/N8jEFAbamq+33XXXSmVSjnyyCOrhAhJsvbaa6dHjx5ZsGBBHnrooZorHj5HkPAVVr9+/Wy11VZZvHhx3nzzzSX2mThxYpJku+22W+o4FTu/VvRd2hjbbrvtypQLK6Wm5nuFRx55JP3790+9evVy00035bDDDqvRemFF1cRcf+655/LGG29k2rRp2WWXXVJeXl75z1577ZUkGT16dMrLy9OtW7dVcyFQQE393b711lsnWXpQULFM/PNfuuDLVFPz/d13303y6X4IS1IRQkydOnVlyoVl8mjDV1znzp3zyiuvZOTIkZVpe4UXX3wx7777brbffvulJvQVY9x2220ZOXJkevXqVaVt/vz5+e9//5sGDRpk1113XSXXAEXVxHxPkqeffjonn3xymjZtmltvvTXbbLPNqiwbltvKzvUNN9wwxx9//BLbPvroo/z5z3/OhhtumAMOOKDae8zhy1YTf7d36tQpdevWzaOPPppFixZV28juxRdfTJKUl5fX/AXAcqiJ+V4RILzxxhtLbJ80aVKSZP3116+ZomEJrEj4ijviiCPSoEGDDBw4MO+//37l8UWLFuWyyy5LkhxzzDGVx99666289tprmTt3buWxrl27ZvPNN88jjzySJ598ssr4N910Uz744IN0794966yzziq+Gli2mpjvc+fOzamnnppFixblT3/6kxCB1dLKzvXNNtssp59++hL/6devX5U+J5xwwpd4ZVBdTfzdvv766+e73/1uJk2alBtvvLHK+A8++GDGjRuX9ddfP7vtttsqvhpYtpqY7xUryW6//fYqYyTJ9OnTc++99yaJNzewStUplUql2i6ClTNw4MD8/ve/zwYbbJDu3bunUaNG+ec//5kXX3wx++23X6644orK57579+6d0aNH54YbbkjXrl0rxxg7dmz69OmTxYsX5+CDD87GG2+cZ599NiNGjMiWW26ZO+64Q5DAamFl5/sNN9yQSy65JNttt126d+++1PN07dq12i8F8GWqib/bl2TKlCnZa6+90rFjxwwaNOjLuBT4QjUx3997770ceeSRmTRpUvbZZ5+0adMmEydOzH333Zf69evnmmuuSZcuXWrrEqHSys73UqmUX/ziFxk+fHhatGiR7t27Z/3118/bb7+dv/3tb5k5c2ZOOOGEnHLKKbV5mXzNebTha+CHP/xhvvWtb+Xmm2/OnXfemYULF2bLLbfMr3/96/Tq1avQ5nEdOnTIXXfdlauvvjoPP/xwZs+enZYtW+aHP/xhTjzxxMpNjKC2rex8f+2115Ik48ePz/jx45far0WLFoIEalVN/N0OXxU1Md/XW2+9/PWvf638b5l///vfady4cfbZZ5+ceOKJhfbPgS/Dys73OnXq5LLLLssee+yRIUOG5N57782cOXPSpEmT7LDDDjnqqKPsf8MqZ0UCAAAAUJg9EgAAAIDCBAkAAABAYYIEAAAAoDBBAgAAAFCYIAEAAAAoTJAAAAAAFCZIAAAAAAoTJAAAAACFCRIAYDk9/fTTOffcc3PggQfm29/+dtq2bZu99torvXv3zi233JIZM2ZU+8yUKVNSXl6e8vLyWqh4+ZxxxhkpLy/PVVddVeX4nDlzcuaZZ2bXXXfN9ttvnx49eiRJrrrqqpSXl+eMM86ohWqX7Kt0vwHgq6Z+bRcAAF8Vc+bMya9//es8+OCDSZLy8vJ85zvfydprr53p06dn1KhRGT16dK644opceOGF2WeffWq54hXTuXPnNGnSJDvuuGOV4zfddFOGDBmSRo0a5Xvf+1422GCDJMmOO+6YY445Jm3btq2NctOlS5d06dIlF1xwQeWxxo0b55hjjqmVegDg665OqVQq1XYRALC6mz9/fnr16pVnn30222yzTX7/+99X++I8c+bMDBgwIIMGDUqdOnVy+eWX57vf/W6ST38h32uvvZIkL7/88pdef0340Y9+lJEjR+bUU09N3759a7ucJMnbb7+dPfbYI4ccckiVIAEAWHU82gAABVxxxRV59tlns+mmm2bQoEFL/PW9efPmOfvss3PsscemVCrl/PPPz0cffVQL1a4a8+bNS5Kst956tVzJ/3nuuedquwQA+MaxIgEAvsCsWbOy5557Zu7cufnjH/9YubJgaebMmZM//elP2X///Suf0V/WioT3338/N910U/7zn/9k8uTJWbBgQVq0aJGddtopP/rRj5YYWowfPz5/+tOfMnbs2Lz33ntZY4010rJly+y555459thj07Jlyyr9n3jiidx6660ZN25cZsyYkcaNG2fDDTfMPvvsk2OOOSZNmzat7HvGGWdk6NCh+elPf5qTTjopV111VQYMGFCthk022SQjRoyobF/SqoC33347119/fUaOHJm33347a665Znbcccf0798/O+20U7Uxn3zyydx222155pln8v7776devXrZZJNN0q1bt/Tr1y9NmjSp7Luk/Q8qalrW/Z4/f37uvvvu3HfffXnttdfy8ccfp3nz5tlxxx1z9NFHp1OnTlX6DxkyJGeeeWb23HPP/PGPf8yf/vSnDB06NNOmTUv9+vXTrl27/OxnP1uuRzvmz5+fO++8Mw888EBeffXVzJkzJ40bN055eXmOPPLIHHDAAUv83PLez6L9n3jiiRxzzDGV9+/zltberVu3TJ06NX/5y1/y+OOPZ9CgQZk5c2aef/75yj6TJ0/OjTfemFGjRmXatGlZtGhR1l9//XTs2DEnnHBCttxyyyVe6yOPPJI77rgjzz33XD788MOsv/762XfffdOvX7+ss846Wbx4cb7zne/k7bffzmWXXZYDDzxwieOcddZZ+ctf/pIf/OAH+e1vf7vkPxAAlos9EgDgCzzyyCOZO3duNthgg3znO9/5wv5rr712fvaznxUae/r06fnBD36Q6dOnZ5NNNsl3v/vdNGjQIC+99FL+/ve/55///Geuu+66dOnSpfIzY8aMyXHHHZcFCxbk29/+drp27ZoFCxbk6aefzo033pjhw4fnjjvuyMYbb5wk+dvf/pZTTz019evXzy677JJNN900H3/8cUaPHp2rrroqDz30UO644440btx4iTVW7IHw97//PdOnT0/nzp2z9dZbp1mzZsu8tmeeeSZ9+/bNrFmzsssuu2S33XbL22+/nZEjR2bkyJH57W9/mx/84AeV/YcMGZJf//rXSZJvf/vb2XPPPTNnzpyMGjUqN9xwQ/71r3/lz3/+c9Zee+0kyTHHHJNx48Zl3Lhx2XrrrdO5c+cvrGnevHn50Y9+lNGjR6dJkybZeeeds9566+XNN9/MiBEj8vDDDy/z0Y1TTz01o0aNyh577JF27dpl9OjRefTRR/PUU0/lvvvuy6abbrrM8yfJokWL0q9fvzz++ONp0qRJdt999zRr1ixvvfVWHn300YwePToTJkyoNoeW934ub/+V8a9//Ss333xz9tlnnzRo0KDy+EsvvZSjjz46s2fPzjbbbJPu3bunVCrl2WefzT333JOHHnoogwcPzrbbbltlvEsvvTTXX399mjRpkq5du2bttdfOM888k4EDB+Zvf/tb/vKXv2TDDTfMIYcckmuuuSZDhgxZYpCwYMGCPPzww0mSnj171si1ApCkBAAs029+85tSWVlZ6ec///kKjzF58uRSWVlZqaysrMrxiy66qFRWVlb6/ve/X/rkk0+qtF1++eWlsrKy0kEHHVTl+PHHH18qKysrDR48uMrxxYsXl84777xSWVlZ6Xe/+13l8f32269UVlZW+s9//lOl//z580s/+clPSmVlZaVbbrml8vjpp59eKisrK1155ZVV+h999NGlsrKy0l//+tcqx6+88spSWVlZ6fTTT688Nm/evNJ3vvOdUllZWemuu+6q0v+xxx4rbbvttqXWrVuX3nrrrVKpVCotWrSo1Llz51JZWVnppptuqtJ/7ty5lddw4403fuG5S6Wl3+9LL720VFZWVtpvv/1K7733XpW2Rx55pFReXl7adtttS+PHj688/te//rVUVlZWateuXemQQw4pzZo1q0pt3bt3L5WVlZWuuOKKUhH//ve/S2VlZaX27duXJk+eXKXt8ccfL5WVlZW233770jvvvFN5fHnv5/L2HzVqVKmsrKz0ne98Z4k1L6294hydOnUqPfvss9U+97Of/axUVlZWOvHEE0uLFi2qPL548eLSaaedViorKyv169evymceffTRUllZWWm33XarrK9U+nSOnHHGGaWysrJSnz59SqVSqTRp0qTKP7Np06ZVO/+//vWvUllZWWnfffdd4nUBsGLskQAAX2D69OlJUujX5uXVtWvXnHPOOTnjjDOyxhprVGk74ogjkiSvvPJKPvzww8rjU6ZMSZK0b9++Sv86derk5z//ee68884qv6gvrX+DBg3ym9/8JnfffXcOPvjgmruofPoL9dSpU7PlllvmsMMOq9K222675YADDsi2226bF198McmnS/1/9atf5fTTT8+hhx5apf9aa62V733ve0k+XY2xohYsWJC77rorSfKrX/0q6667bpX2rl27Zq+99srixYtz9913V/v83Llz87//+79VHgNZa621st9++yUpvonmpptumvPOOy+/+c1vqs2pTp06ZbPNNsvChQszbty4yuPLez+Xt//KKi8vzw477FDt+MEHH5yzzjorJ598curW/b//7KxTp07laojP/5kOGjQoSXLsscdmo402qjxet27dnHTSSdl6660zb968fPzxx/nWt76VXXbZJYsXL87QoUOrnX/48OFJrEYAqGkebQCALzB37twkn35prGm77LJLdtlllyW2fXafg9mzZ1d+gd1yyy3zxhtv5Le//W3OO++8bLHFFpX9GjduXC0w2HLLLfPKK6/krLPOyq9//esq46677rrVvlDXhCeeeCJJsvPOOy+x/dJLL63y72uuueYyw4yKmmfPnr3CNU2YMCEzZ85MvXr1svvuuy+xz2677ZaHH344Tz/9dLW2hg0bLnEfhIrXYBatbeutt87WW2+91PaWLVtm0qRJVcZb3vu5vP1X1tLm8LIeBVrSn2mpVKqsvUOHDtU+s/HGG1eGAxUOPfTQjBo1KkOHDs2JJ55YeXz+/Pn55z//mbp166ZHjx6FrwWALyZIAIAvULF3wKp6A8Po0aNzxx135IUXXsgHH3ywxPOUPrM38q9//eu88MILGT16dPbbb7+Ul5enU6dO2X333bPLLrtUeUY9Sc4///wcd9xxefDBB/PQQw9lhx12qOy/0047VfmluKZMnTo1Sapt+rgs8+fPz+DBg/PQQw9l8uTJ+eCDD7JgwYIaq6liZcb666+fhg0bLrHPJptskiSZNm1atbaWLVumTp061Y7Xq1cvSdU/oy8yadKkDBw4ME8++WTeeeedzJo1q9rnP/vvy3s/V+T+r4xlhVEPP/xw/vKXv+SVV17JjBkzKoO5Jflse9Ha99133zRt2jRvvvlmxowZUxmePPLII/noo4/SpUuXL+0+AHxTCBIA4AtUbFo4ceLEGh/7tttuy29/+9uUSqW0bNkyXbt2TYsWLSq/nN56663VPrPZZptl2LBhlRvPvfzyy3n55ZczcODArLPOOunfv3969+5d2b9t27a5//77c+ONN+bvf/975QaF1157bTbZZJP88pe/XOpbAlZUxasi69cv9p8a8+fPz7HHHpunnnoqderUSdu2bbPbbrtVvqXhtddey2OPPbZSNX388cdJPl39sDQVj5d88skn1dqKXssXeeaZZ3L88cdnzpw5WXvttdOxY8dssMEGleeu2NTys5b3fi5v/5XVqFGjJR6/8MILc9NNNyX5dN7utddeadasWerWrZuPPvooQ4YMqdJ//vz5lf/784HY0qyxxhrp3r17br/99vz1r3+tDBIqVi58//vfX+7rAWDZBAkA8AXat2+fgQMHZsyYMfnkk0+W+UW0wvz585f6q3eFDz74IBdccEFKpVJOOumk/OQnP6nyi/fixYuXGCQkSYsWLXLKKafklFNOyZtvvplHH300DzzwQJ588sn89re/zaJFi/LDH/6wsv9GG22Us88+O2effXZeeeWVjBw5Mvfff39efPHFnHLKKWnYsGH23nvvYjekgIrHQD67t8OyDB48OE899VSaNGmS2267rdou/n/5y19WOkio+LJbESgsSUVbxZshVoVzzz03c+bMyR577JErrrii2iMzL774YrUgYXnv5/L2/yILFy5c7s+89NJLlSHC73//+2r7FEyePLlakPDZezFr1qzCKwkOPfTQ3H777fn73/+ec889N4sWLcq///3vNG3atEbnNQCfstkiAHyBrl27pmnTppk9e3a1Lz5LsmjRohx22GE59dRT88477yy139NPP50FCxakSZMmOfHEE6stm588eXKh+jbffPP06tUrt912W/7f//t/SZLbb799qf3LysrSp0+fDB06NP369Uvy6cqImvStb30rSap9IV6aJ598Msmnm/N9PkRIit+LIjW9++67S1xx8NnzrIqNNZNPH48ZP358kuTkk09e4r4bS7rW5b2fy9u/4vGWRYsWLbG94lGJ5TF69Ogkn863JW12uKTrbNasWeUrPIvWniTbb799WrdunTlz5uSRRx7JP//5z8ydOzcHHnjgFwZ6ACw/QQIAfIFGjRrl+OOPT5Jcfvnlef3115fZ/7LLLsv48eMzduzYpS75Tv7vS1vjxo0rH2X4rMGDB1f+74rn5WfNmpUHHngg//nPf5Y45kEHHZTk/76EvfPOO7n33nvz1FNPFepfUyo23xs9evQS9zk45ZRTsv322+ePf/xjkv/7xfuzb0So8PHHH+fee+9NsvR9CIrsT9CqVau0aNEiixcvXur9GzlyZJKkY8eOXzjeivjsL/sVX5g/a8SIEZV/Fp+9puW9n8vbv2IFxowZM5a4+uDRRx8tdoGfUTG/l/Rnmix5fif/d++XtAJl9uzZadu2bVq3bp233nqrSlvFIwz3339/7rvvviTe1gCwqggSAKCAvn37Ztddd82HH36Yo48+Og8//HC1Ph988EHOOeec/OlPf0qjRo1y0UUXVW7UuCQVO/e//fbblb9SVxg8eHBGjhyZddZZp7JPkrz33ns55ZRTcvrpp+e1116rNmbFc+Hbbbddkk9fSXjaaaflzDPPXOLqiM/3ryldu3bN5ptvnnfffTdXXXVVlbZnnnkmDz/8cOrWrZsDDzwwyf/di5EjR1b5VXzWrFn5+c9/XrkJYsV9qFDxBfjzXyqXpF69epV7R1x66aX54IMPqrQ/+OCDGTlyZNZcc81qr0ysKc2bN6/cmPBf//pXlbYxY8bk//2//5c2bdokqbrh4/Lez+Xtv8UWW6RBgwaZN29e5ZfwCsOHD1+hx0q22mqrJNUf1Vi4cGGuuOKKvPvuu5UrIT57rUcffXSS5K677qryespSqZQrr7wy8+bNy0477VS5d0mF7t27Z4011sgjjzySxx57LNtss80S37IBwMqzRwIAFFCvXr1cf/31OffcczN06ND85Cc/yaabbpp27dqladOmmT59ev773/9m7ty52WijjXL11VendevWyxxz6623zne+853861//Sq9evbLXXnulYcOGeeqpp/Lee+/l5ptvzpVXXplHHnkkZ599dnbdddf85je/Sb9+/XLttdfm4IMPTseOHbPppptm8eLFee211/L000+nUaNGOf3005Mku+++e7p375777rsv++67b3bddde0bNkyCxYsyPjx4/Piiy9mnXXWycknn1yj96tBgwa55JJLcvzxx+e6667L448/nu233z7vvPNOZVhw5plnZvPNN0/y6ZfHO+64I88991wOPvjg7LTTTpk5c2Yee+yxtGnTJhdffHH23nvvTJ48OSeccEL233//9OjRo/JL9+jRo3PEEUdUnndp+vbtm7Fjx+axxx7Ld7/73XTs2DFNmzatvHf169fPeeedt8oebUiSH//4x7ngggvy+9//Po8//nhatmyZV199NU8//XR+85vfZNasWXn++edz880355133skPf/jDbLXVVst1P5f3/jdq1CiHHnpoBg8enF//+td58MEHs9FGG+WNN97ImDFjcu655+ass85aruvs0qVLtttuu4wfPz6HHHJI9thjj8rXO5ZKpdx2223p169fXn311fzkJz/JHnvskZ///OfZddddc8IJJ+Taa6/NEUcckT322CMtWrTIM888k5dffjnrrbdezjvvvGrna9q0afbdd9/KIOSQQw5ZyT8pAJZGkAAABa2xxhr5/e9/n169emXo0KEZNWpUHnnkkXz88cdp2rRp2rVrl3322Sc9e/YstCFjklx00UW55JJLMmLEiDzwwANZf/31s+uuu6Zfv37ZYost8otf/CLTpk3L66+/XrmPwCmnnJI2bdrkr3/9a1588cWMGTMmpVIpG2+8cQ477LAcf/zx2WKLLSrPcfHFF6dTp06577778vzzz+fRRx9N/fr1s+mmm+a4447L8ccfnw022KDG71fbtm0zbNiwXHvttXn00UczZMiQrLXWWtl1113zox/9KJ06darsu9FGG+XGG2/MH/7whzz33HOZOnVqvvWtb+WEE07Isccem4YNG+aXv/xlrr/++owaNSo77LBDkk+XwZ9wwgmVv15vtNFGqVev3lJfG9mgQYNcd911+fOf/5z77rsvjz32WObPn59111033bt3z/HHH5/tt9++xu/FZx177LFZtGhR7r777jz66KNp2rRptt9++9x4443p1KlTZs+enVGjRuXJJ5/MiBEjctRRRy33/VyR/meddVZatGhReV/WXnvttGnTJgMHDlyhYKVevXq57rrrctFFF+XRRx/N/fffn5YtW2avvfZK3759s8EGG+Tss8/OOeeckwkTJlSuvkk+nePt2rXLbbfdltGjR2fOnDlZf/31c9RRR+XEE09c6nw99NBDc99996VevXo5+OCDl7tmAIqpU1qelx4DAMBq6pFHHknfvn2z33775corr6ztcgC+tuyRAADA18I111yT5NNVHwCsOoIEAAC+8q688so8/fTT6dSpUzp06FDb5QB8rXm0AQCAr6Snn346999/f8aNG5fnnnsu66yzTu6+++5VulkmAFYkAADwFTV16tTcfvvtee211/Kd73wnd955pxAB4EtgRQIAAABQmBUJAAAAQGGCBAAAAKAwQQIAAABQmCABAAAAKEyQAAAAABQmSAAAAAAK+//osHOLIzChCQAAAABJRU5ErkJggg==\n", "text/plain": [ - "
" + "
" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", + "import seaborn\n", + "plt.style.use('seaborn-white')\n", + "seaborn.set_context('poster')\n", "mean_scores = [np.mean(scores[kind]) for kind in kinds]\n", "print(list(zip(mean_scores, kinds) ))\n", "scores_std = [np.std(scores[kind]) for kind in kinds]\n", "\n", - "plt.figure(figsize=(10, 8))\n", + "plt.figure(figsize=(15, 10))\n", "positions = np.arange(len(kinds)) * .1 + .1\n", "plt.barh(positions, mean_scores, align='center', height=.05, xerr=scores_std)\n", "yticks = [k.replace(' ', '\\n') for k in kinds]\n", "plt.yticks(positions, yticks)\n", "plt.gca().grid(True)\n", "plt.gca().set_axisbelow(True)\n", - "plt.gca().axvline(.8, color='red', linestyle='--')\n", - "plt.xlabel('Classification accuracy\\n(red line = chance level)')\n", - "plt.tight_layout()" + "plt.xlabel('Classification accuracy')\n", + "plt.tight_layout()\n", + "plt.savefig('accuracy.png', bbox_inches=\"tight\", dpi=300)" ] }, { From e8c86b77e425049d16eeb4d8781448c6b6373a15 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood Date: Tue, 20 Jul 2021 20:28:56 +0100 Subject: [PATCH 7/8] 0.14.0 version bump --- Cargo.toml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78d7910..2dad7fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-dtw" -version = "0.1.13" +version = "0.1.14" authors = ["Christopher Fleetwood"] edition = "2018" description = "A rust implementation of dynamic time warping with python bindings!" diff --git a/pyproject.toml b/pyproject.toml index f67419e..1b1a924 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ build-backend = "maturin" [tool.poetry] name = "rust-dtw" -version = "0.1.13" +version = "0.1.14" description = "A rust implementation of dynamic time warping with python bindings!" license = "MIT" readme = "README.md" From 37ab548c34e041d969083ac1f1ae84d3d941c014 Mon Sep 17 00:00:00 2001 From: Christopher Fleetwood <45471420+FL33TW00D@users.noreply.github.com> Date: Tue, 20 Jul 2021 20:36:34 +0100 Subject: [PATCH 8/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb6a588..93ac327 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ poetry run pytest

-The above shows the performance of the rustdtw implementation vs the DTAIDistance OpenMP Python version (more benchmarks vs C implementation coming soon). +The above shows the performance of the rustdtw implementation vs the DTAIDistance OpenMP Python version, showing a ~10x speed improvement. ## ⚠️ License