diff --git a/scripts/analyse-collaborative-complex.ipynb b/scripts/analyse-collaborative-complex.ipynb new file mode 100644 index 0000000..660670b --- /dev/null +++ b/scripts/analyse-collaborative-complex.ipynb @@ -0,0 +1,446 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "\n", + "import re\n", + "import json\n", + "import statistics\n", + "import argparse\n", + "import itertools\n", + "from pathlib import Path\n", + "from dataclasses import dataclass\n", + "\n", + "# print(f\"{os.getcwd()=}\")\n", + "\n", + "from ldj import ldj\n", + "from utils import *\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "# from matplotlib.font_manager import FontProperties\n", + "import matplotlib.font_manager as fm\n", + "from matplotlib.patches import FancyBboxPatch\n", + "from matplotlib.patches import PathPatch\n", + "from matplotlib.path import get_path_collection_extents\n", + "import seaborn as sns\n", + "\n", + "from rich import print, pretty\n", + "from tabulate import tabulate\n", + "from typing import Iterable\n", + "import pretty_errors\n", + "from catppuccin import PALETTE\n", + "from IPython.display import display, HTML\n", + "\n", + "pretty.install()\n", + "\n", + "EXPERIMENT_DIR = Path(\"../experiments/collaborative-complex\")\n", + "assert EXPERIMENT_DIR.is_dir() and EXPERIMENT_DIR.exists()\n", + "\n", + "flavor = PALETTE.latte.colors\n", + "\n", + "data = dict()\n", + "\n", + "@dataclass\n", + "class Results:\n", + " with_tracking: dict\n", + " without_tracking: dict\n", + "\n", + "results = Results(dict(), dict())\n", + "\n", + "with open(EXPERIMENT_DIR / \"tracking-true.json\") as f:\n", + " results.with_tracking = json.load(f)\n", + "\n", + "with open(EXPERIMENT_DIR / \"tracking-false.json\") as f:\n", + " results.without_tracking = json.load(f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass(frozen=True)\n", + "class Statistics:\n", + " mean: float\n", + " median: float\n", + " stdev: float\n", + " min: float\n", + " max: float\n", + "\n", + "\n", + " def display(self) -> None:\n", + " data = [\n", + " [\"Mean\", self.mean],\n", + " [\"Median\", self.median],\n", + " [\"Standard Deviation\", self.stdev],\n", + " [\"Min\", self.min],\n", + " [\"Max\", self.max]\n", + " ]\n", + " html_table = tabulate(data, headers=[\"Statistic\", \"Value\"], tablefmt=\"html\")\n", + " centered_html_table = f\"\"\"\n", + "
\n", + " {html_table}\n", + "
\n", + " \"\"\"\n", + " # display(HTML(html_table))\n", + " display(HTML(centered_html_table))\n", + " # print(tabulate(data, headers=[\"Statistic\", \"Value\"], tablefmt=\"html\"))\n", + "\n", + "\n", + "def compute_stats(data: list[float]) -> Statistics:\n", + " return Statistics(\n", + " mean=np.mean(data),\n", + " median=np.median(data),\n", + " stdev=np.std(data),\n", + " min=np.min(data),\n", + " max=np.max(data),\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass(frozen=True)\n", + "class PerpendicularPositionErrorResult:\n", + " errors: list[float]\n", + " rmses: list[float]\n", + "\n", + "\n", + "def perpendicular_position_error(exported_data: dict) -> PerpendicularPositionErrorResult:\n", + " errors: list[float] = []\n", + " rmses: list[float] = []\n", + "\n", + " for robot_id, robot_data in exported_data['robots'].items():\n", + " color: str = robot_data['color']\n", + " positions = np.array([p for p in robot_data['positions']])\n", + " mission = robot_data['mission']\n", + " waypoints = []\n", + " for route in mission['routes']:\n", + " waypoints.append(route['waypoints'][0])\n", + " for wp in route['waypoints'][1:]:\n", + " waypoints.append(wp)\n", + "\n", + " waypoints = np.array(waypoints)\n", + " waypoints = np.squeeze(waypoints)\n", + "\n", + " lines: list[LinePoints] = [LinePoints(start=start, end=end) for start, end in sliding_window(waypoints, 2)]\n", + " closest_projections = [closest_projection_onto_line_segments(p, lines) for p in positions]\n", + "\n", + " error: float = np.sum(np.linalg.norm(positions - closest_projections, axis=1))\n", + " rmse: float = np.sqrt(error / len(positions))\n", + "\n", + " errors.append(error)\n", + " rmses.append(rmse)\n", + "\n", + " return PerpendicularPositionErrorResult(errors=errors, rmses=rmses)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass(frozen=True)\n", + "class CollisionsResult:\n", + " interrobot: int\n", + " environment: int\n", + "\n", + "def collisions(exported_data: dict) -> CollisionsResult:\n", + " interrobot: int = len(exported_data['collisions']['robots'])\n", + " environment: int = len(exported_data['collisions']['environment'])\n", + " return CollisionsResult(interrobot=interrobot, environment=environment)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# With Tracking" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Makespan" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
makespan = 159.92 seconds\n",
+       "
\n" + ], + "text/plain": [ + "makespan = \u001b[1;36m159.92\u001b[0m seconds\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(f\"makespan = {results.with_tracking['makespan']:.2f} seconds\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perpendicular Position Error" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "        
\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Statistic Value
Mean 113.23
Median 107.61
Standard Deviation 47.0414
Min 9.9365e-13
Max 316.921
\n", + "
\n", + " " + ], + "text/plain": [ + "\u001b[1m<\u001b[0m\u001b[1;95mIPython.core.display.HTML\u001b[0m\u001b[39m object\u001b[0m\u001b[1m>\u001b[0m" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pperror = perpendicular_position_error(results.with_tracking)\n", + "compute_stats(pperror.errors).display()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collisions" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;35mCollisionsResult\u001b[0m\u001b[1m(\u001b[0m\u001b[33minterrobot\u001b[0m=\u001b[1;36m0\u001b[0m, \u001b[33menvironment\u001b[0m=\u001b[1;36m90\u001b[0m\u001b[1m)\u001b[0m"
+      ]
+     },
+     "execution_count": 60,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "collisions(results.with_tracking)\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Without Tracking"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
makespan = 160.34 seconds\n",
+       "
\n" + ], + "text/plain": [ + "makespan = \u001b[1;36m160.34\u001b[0m seconds\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(f\"makespan = {results.without_tracking['makespan']:.2f} seconds\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perpendicular Position Error" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "        
\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Statistic Value
Mean 113.23
Median 107.61
Standard Deviation 47.0414
Min 9.9365e-13
Max 316.921
\n", + "
\n", + " " + ], + "text/plain": [ + "\u001b[1m<\u001b[0m\u001b[1;95mIPython.core.display.HTML\u001b[0m\u001b[39m object\u001b[0m\u001b[1m>\u001b[0m" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pperror = perpendicular_position_error(results.without_tracking)\n", + "compute_stats(pperror.errors).display()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collisions" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;35mCollisionsResult\u001b[0m\u001b[1m(\u001b[0m\u001b[33minterrobot\u001b[0m=\u001b[1;36m0\u001b[0m, \u001b[33menvironment\u001b[0m=\u001b[1;36m90\u001b[0m\u001b[1m)\u001b[0m"
+      ]
+     },
+     "execution_count": 63,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "collisions(results.without_tracking)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "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.11.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}