diff --git a/flatland/evaluators/service.py b/flatland/evaluators/service.py index d77f8cbbd6a9d40c172c20d386dda174cd6bc19a..66532cf1e680de6fb878f6b4709d7dfd98c9aab4 100644 --- a/flatland/evaluators/service.py +++ b/flatland/evaluators/service.py @@ -49,9 +49,8 @@ m.patch() # CONSTANTS ######################################################## -# Don't proceed to next Test if the previous one -# didn't reach this mean completion percentage -TEST_MIN_PERCENTAGE_COMPLETE_MEAN = 0.25 +# Don't proceed to next Test if the previous one didn't reach this mean completion percentage +TEST_MIN_PERCENTAGE_COMPLETE_MEAN = float(os.getenv("TEST_MIN_PERCENTAGE_COMPLETE_MEAN", 0.25)) # After this number of consecutive timeouts, kill the submission: # this probably means the submission has crashed @@ -159,6 +158,14 @@ class FlatlandRemoteEvaluationService: print("Env shuffling is ENABLED! not suitable for infinite wave") print("=" * 20) + print("=" * 20) + print("Max pre-planning time:", INTIAL_PLANNING_TIMEOUT) + print("Max step time:", PER_STEP_TIMEOUT) + print("Max overall time:", OVERALL_TIMEOUT) + print("Max submission startup time:", DEFAULT_COMMAND_TIMEOUT) + print("Max consecutive timeouts:", MAX_SUCCESSIVE_TIMEOUTS) + print("=" * 20) + # Test Env folder Paths self.test_env_folder = test_env_folder self.video_generation_envs = video_generation_envs @@ -394,7 +401,6 @@ class FlatlandRemoteEvaluationService: self.evaluation_metadata_df["nb_malfunctioning_trains"] = np.nan self.evaluation_metadata_df["nb_deadlocked_trains"] = np.nan - # Add client specific columns # TODO: This needs refactoring self.evaluation_metadata_df["controller_inference_time_min"] = np.nan @@ -423,55 +429,55 @@ class FlatlandRemoteEvaluationService: # generate the lists of names for the stats (input names and output names) sPrefixIn = "current_episode_controller_inference_time_" sPrefixOut = "controller_inference_time_" - lsStatIn = [ sPrefixIn + sStat for sStat in ["min", "mean", "max"] ] - lsStatOut = [ sPrefixOut + sStat for sStat in ["min", "mean", "max"] ] + lsStatIn = [sPrefixIn + sStat for sStat in ["min", "mean", "max"]] + lsStatOut = [sPrefixOut + sStat for sStat in ["min", "mean", "max"]] if lsStatIn[0] in self.stats: - lrStats = [ self.stats[sStat] for sStat in lsStatIn ] + lrStats = [self.stats[sStat] for sStat in lsStatIn] else: - lrStats = [ 0.0 ] * len(lsStatIn) - - lsFields = ("reward, normalized_reward, percentage_complete, " +\ - "steps, simulation_time, nb_malfunctioning_trains, nb_deadlocked_trains").split(", ") +\ - lsStatOut - - loValues = [ self.simulation_rewards[-1], - self.simulation_rewards_normalized[-1], - self.simulation_percentage_complete[-1], - self.simulation_steps[-1], - self.simulation_times[-1], - self.nb_malfunctioning_trains[-1], - self.nb_deadlocked_trains[-1] - ] + lrStats + lrStats = [0.0] * len(lsStatIn) + + lsFields = ("reward, normalized_reward, percentage_complete, " + \ + "steps, simulation_time, nb_malfunctioning_trains, nb_deadlocked_trains").split(", ") + \ + lsStatOut + + loValues = [self.simulation_rewards[-1], + self.simulation_rewards_normalized[-1], + self.simulation_percentage_complete[-1], + self.simulation_steps[-1], + self.simulation_times[-1], + self.nb_malfunctioning_trains[-1], + self.nb_deadlocked_trains[-1] + ] + lrStats # update the dataframe without the updating-a-copy warning df = self.evaluation_metadata_df df.loc[last_simulation_env_file_path, lsFields] = loValues - #_row.reward = self.simulation_rewards[-1] - #_row.normalized_reward = self.simulation_rewards_normalized[-1] - #_row.percentage_complete = self.simulation_percentage_complete[-1] - #_row.steps = self.simulation_steps[-1] - #_row.simulation_time = self.simulation_times[-1] - #_row.nb_malfunctioning_trains = self.nb_malfunctioning_trains[-1] - - #_row.controller_inference_time_min = self.stats[ - # "current_episode_controller_inference_time_min" - #] - #_row.controller_inference_time_mean = self.stats[ - # "current_episode_controller_inference_time_mean" - #] - #_row.controller_inference_time_max = self.stats[ - # "current_episode_controller_inference_time_max" - #] - #else: + # _row.reward = self.simulation_rewards[-1] + # _row.normalized_reward = self.simulation_rewards_normalized[-1] + # _row.percentage_complete = self.simulation_percentage_complete[-1] + # _row.steps = self.simulation_steps[-1] + # _row.simulation_time = self.simulation_times[-1] + # _row.nb_malfunctioning_trains = self.nb_malfunctioning_trains[-1] + + # _row.controller_inference_time_min = self.stats[ + # "current_episode_controller_inference_time_min" + # ] + # _row.controller_inference_time_mean = self.stats[ + # "current_episode_controller_inference_time_mean" + # ] + # _row.controller_inference_time_max = self.stats[ + # "current_episode_controller_inference_time_max" + # ] + # else: # _row.controller_inference_time_min = 0.0 # _row.controller_inference_time_mean = 0.0 # _row.controller_inference_time_max = 0.0 - #self.evaluation_metadata_df.loc[ + # self.evaluation_metadata_df.loc[ # last_simulation_env_file_path - #] = _row + # ] = _row # Delete this key from the stats to ensure that it # gets computed again from scratch in the next episode @@ -676,7 +682,7 @@ class FlatlandRemoteEvaluationService: if self.simulation_count >= len(self.env_file_paths): self.evaluation_done = True # Hack - just ensure these are set - test_env_file_path = self.env_file_paths[self.simulation_count-1] + test_env_file_path = self.env_file_paths[self.simulation_count - 1] env_test, env_level = self.get_env_test_and_level(test_env_file_path) else: test_env_file_path = self.env_file_paths[self.simulation_count] @@ -692,7 +698,8 @@ class FlatlandRemoteEvaluationService: if mean_test_complete_percentage < TEST_MIN_PERCENTAGE_COMPLETE_MEAN: print("=" * 15) - msg = "The mean percentage of done agents during the last 10 environments was too low: {:.3f} < {}".format( + msg = "The mean percentage of done agents during the last Test ({} environments) was too low: {:.3f} < {}".format( + len(self.simulation_percentage_complete_per_test[self.current_test]), mean_test_complete_percentage, TEST_MIN_PERCENTAGE_COMPLETE_MEAN ) @@ -901,7 +908,7 @@ class FlatlandRemoteEvaluationService: if len(self.env.cur_episode) > 0: g3Ep = np.array(self.env.cur_episode) - self.nb_deadlocked_trains.append(np.sum(g3Ep[-1,:,5])) + self.nb_deadlocked_trains.append(np.sum(g3Ep[-1, :, 5])) else: self.nb_deadlocked_trains.append(np.nan) @@ -1223,11 +1230,11 @@ class FlatlandRemoteEvaluationService: self.evaluation_done = True # JW - change the command to a submit print("Creating fake submit message after excessive timeouts.") - command = { - "type":messages.FLATLAND_RL.ENV_SUBMIT, + command = { + "type": messages.FLATLAND_RL.ENV_SUBMIT, "payload": {}, - "response_channel": self.previous_command.get("response_channel") } - + "response_channel": self.previous_command.get("response_channel")} + return self.handle_env_submit(command) continue diff --git a/notebooks/test-service-timeouts.ipynb b/notebooks/test-service-timeouts.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..67a849d8e8df06c6fa0b4dc253aa0ebe553aa4d9 --- /dev/null +++ b/notebooks/test-service-timeouts.ipynb @@ -0,0 +1,841 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Service\n", + "\n", + "Intended to test the service.py evaluator.\n", + "Runs the service.py and a simple client." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "baXcVq3ii0Cb" + }, + "source": [ + "Setup\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import PIL\n", + "from flatland.utils.rendertools import RenderTool\n", + "import imageio\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "PU5GkH271guD" + }, + "outputs": [], + "source": [ + "from flatland.envs.rail_env import RailEnv\n", + "from flatland.envs.rail_generators import sparse_rail_generator\n", + "from flatland.envs.schedule_generators import sparse_schedule_generator\n", + "from flatland.envs.malfunction_generators import malfunction_from_file, no_malfunction_generator\n", + "from flatland.envs.rail_generators import rail_from_file\n", + "from flatland.envs.schedule_generators import schedule_from_file\n", + "from flatland.core.env_observation_builder import DummyObservationBuilder\n", + "from flatland.envs.persistence import RailEnvPersister\n", + "from flatland.evaluators.client import FlatlandRemoteClient, TimeoutException\n", + "import flatland.evaluators.service as fes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "PU5GkH271guD" + }, + "outputs": [], + "source": [ + "import pickle\n", + "import redis\n", + "import subprocess as sp\n", + "import shlex\n", + "import time\n", + "import pkg_resources as pr\n", + "import importlib_resources as ir\n", + "import sys, os\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sDirRoot = \"/Users/flaurent/Sites/flatland/neurips2020-flatland-starter-kit/scratch/test-neurips2020-round2-v0\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!ps -ef | grep -i python | grep -i flatland.evaluators.service" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def kill_evaluator():\n", + " # kill previous evaluator\n", + " !ps -ef | grep -i python | grep -i flatland.evaluators.service | awk '{print $2}' | xargs kill" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def cleanup():\n", + " oRedis = redis.Redis()\n", + " lKeys = oRedis.keys(\"flatland*\")\n", + " for sKey in lKeys:\n", + " print(\"Deleting:\", sKey)\n", + " oRedis.delete(sKey)\n", + " \n", + " !rm -f /tmp/output.csv\n", + " \n", + " kill_evaluator()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def configure_env(overall=8*60*60, planning=5*60, step=10, successive=10, mean_percentage=0.25):\n", + " osEnv2 = os.environ.copy()\n", + " osEnv2[\"FLATLAND_OVERALL_TIMEOUT\"]=str(overall)\n", + " osEnv2[\"FLATLAND_PER_STEP_TIMEOUT\"] = str(step)\n", + " osEnv2[\"FLATLAND_INITIAL_PLANNING_TIMEOUT\"] = str(planning)\n", + " osEnv2[\"FLATLAND_MAX_SUCCESSIVE_TIMEOUTS\"] = str(successive)\n", + " osEnv2[\"TEST_MIN_PERCENTAGE_COMPLETE_MEAN\"] = str(mean_percentage)\n", + " return osEnv2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def start_evaluator(env):\n", + " sCmd = f\"python -m flatland.evaluators.service --test_folder {sDirRoot} --pickle\" # --verbose\"\n", + " lsCmd = shlex.split(sCmd)\n", + " print(sCmd)\n", + " \n", + " oPipe = sp.Popen(lsCmd, env=env)\n", + " oPipe.poll()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def start_client():\n", + " oFRC = FlatlandRemoteClient(test_envs_root=sDirRoot, verbose=False, use_pickle=True)\n", + " env, env_dict = RailEnvPersister.load_new(f\"{sDirRoot}/Test_0/Level_0.pkl\")\n", + " return oFRC" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def random_controller(obs, _env):\n", + " np.random.seed(0)\n", + " \n", + " dAct = {}\n", + " for iAg in range(len(_env.agents)):\n", + " dAct[iAg] = np.random.randint(0, 5)\n", + " return dAct" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def run_submission(oFRC, slow_ep=-1, debug=False):\n", + " def log(txt, end=\"\\n\"):\n", + " if debug: print(txt, end)\n", + " \n", + " dummy_obs = DummyObservationBuilder()\n", + " episode = 0\n", + " obs = True\n", + " \n", + " while obs:\n", + " obs, info = oFRC.env_create(obs_builder_object=dummy_obs)\n", + " log(oFRC.current_env_path)\n", + " log(f\"Episode : {episode}\")\n", + " \n", + " if not obs:\n", + " log(\"None observation - all envs completed!\")\n", + " break\n", + " \n", + " while True:\n", + " action = random_controller(obs, oFRC.env)\n", + " \n", + " if slow_ep != -1:\n", + " # make a specific episode artificially slow\n", + " if (episode == slow_ep) and (oFRC.env._elapsed_steps > 10):\n", + " time.sleep(2)\n", + " \n", + " try:\n", + " observation, all_rewards, done, info = oFRC.env_step(action)\n", + " #log(\".\", end=\"\")\n", + " if done['__all__']:\n", + " log(\"\\nCompleted Episode : \", episode)\n", + " log(\"Reward : \", sum(list(all_rewards.values())))\n", + " break\n", + " except TimeoutException as err:\n", + " log(\"Timeout: \", err)\n", + " break\n", + " \n", + " episode += 1\n", + " \n", + " #print(f\"Evaluation Complete - episodes={episode} - send submit message...\")\n", + " #print(oFRC.submit())\n", + " #print(\"All done.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tests\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# Normal submission\n", + "cleanup()\n", + "config = configure_env(overall=8*60*60, planning=5*60, step=10, successive=10, mean_percentage=0.1)\n", + "start_evaluator(config)\n", + "client = start_client()\n", + "run_submission(client)\n", + "\n", + "#try:\n", + "# run_submission(client)\n", + "#except Exception as e:\n", + "# print(\"== EXCEPTION! ===\")\n", + "# print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# Overall timeout\n", + "cleanup()\n", + "config = configure_env(overall=3, planning=5*60, step=10, successive=10, mean_percentage=0.0)\n", + "start_evaluator(config)\n", + "client = start_client()\n", + "run_submission(client, debug=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# Step timeout\n", + "# FIXME fails!\n", + "\"\"\"\n", + "cleanup()\n", + "config = configure_env(overall=3, planning=5*60, step=10, successive=10, mean_percentage=0.0)\n", + "start_evaluator(config)\n", + "client = start_client()\n", + "run_submission(client, slow_ep=2, debug=True)\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#pd.read_csv(\"/tmp/output.csv\").T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cleanup\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "kill_evaluator()" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Flatland Round 2 Replays", + "provenance": [] + }, + "hide_input": false, + "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.8" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "0dd673bfc308419c8f62c545999562b3": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "1bc1201efe3e4e3a8403e4b8c902a295": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "26afede661e541db9d09f4bd88895c7b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatSliderModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatSliderModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "FloatSliderView", + "continuous_update": true, + "description": "frame_idx", + "description_tooltip": null, + "disabled": false, + "layout": "IPY_MODEL_e042a431167b452a9e9f2f0a0ac99f45", + "max": 29, + "min": 0, + "orientation": "horizontal", + "readout": true, + "readout_format": ".2f", + "step": 1, + "style": "IPY_MODEL_40b60736128543f48f32eb1f7c89d855", + "value": 0 + } + }, + "40b60736128543f48f32eb1f7c89d855": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "SliderStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "SliderStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "", + "handle_color": null + } + }, + "4a12b47571a0481b881e564bbbcf6f53": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_78910a9b607e4a47b06b5c2cf03811a7" + ], + "layout": "IPY_MODEL_1bc1201efe3e4e3a8403e4b8c902a295" + } + }, + "55f6067b15be4de4b9ab165d4ff7009b": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_f8b98bf694c848baa97f2ef4e9e599db", + "msg_id": "", + "outputs": [] + } + }, + "78910a9b607e4a47b06b5c2cf03811a7": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "PlayModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "PlayModel", + "_playing": false, + "_repeat": false, + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "PlayView", + "description": "", + "description_tooltip": null, + "disabled": false, + "interval": 250, + "layout": "IPY_MODEL_a8de6f99082e428dae860e4c6a79b9cc", + "max": 29, + "min": 0, + "show_repeat": true, + "step": 1, + "style": "IPY_MODEL_0dd673bfc308419c8f62c545999562b3", + "value": 0 + } + }, + "86c96853eb074ec18c60567cd4e8b134": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [ + "widget-interact" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_26afede661e541db9d09f4bd88895c7b", + "IPY_MODEL_55f6067b15be4de4b9ab165d4ff7009b" + ], + "layout": "IPY_MODEL_bb522116f06a4f1babe2a3c0c557654d" + } + }, + "a8de6f99082e428dae860e4c6a79b9cc": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bb522116f06a4f1babe2a3c0c557654d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e042a431167b452a9e9f2f0a0ac99f45": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f8b98bf694c848baa97f2ef4e9e599db": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}