{ "cells": [ { "cell_type": "markdown", "id": "d32c2081-76d0-4c47-98d0-228a14e8073a", "metadata": {}, "source": [ "## Legacy heuristic examples" ] }, { "cell_type": "markdown", "id": "b306a7d8-a29e-41c5-a537-c20e702133dd", "metadata": {}, "source": [ "`ClassicEW`, `CPEW`, `NBEW`, and `OBEW` are deprecated legacy heuristic entry points. They will be removed in version 0.3.\n", "\n", "Their functionality is now available through the unified `constructor()` heuristic.\n", "\n", "This notebook contains examples of each of the legacy entry points usage and the equivalent call to `constructor()`.\n", "\n", "The unified heuristic **does not reproduce exactly** the deprecated heuristics, but the properties of the solution should match." ] }, { "cell_type": "code", "execution_count": 1, "id": "2ea0ea53-31b1-4099-bab6-d66d62770719", "metadata": {}, "outputs": [], "source": [ "import warnings\n", "\n", "from optiwindnet.importer import load_repository\n", "from optiwindnet.mesh import make_planar_embedding\n", "from optiwindnet.pathfinding import PathFinder\n", "from optiwindnet.heuristics import ClassicEW, CPEW, NBEW, OBEW, constructor\n", "from optiwindnet.interarraylib import G_from_S, calcload\n", "from optiwindnet.svg import svgplot" ] }, { "cell_type": "code", "execution_count": 2, "id": "4d4e57f9-ab96-43fc-95ec-9c874c25d02d", "metadata": {}, "outputs": [], "source": [ "locations = load_repository()" ] }, { "cell_type": "markdown", "id": "ec84aca7-34f3-49a4-ab3b-ecf93318fec2", "metadata": {}, "source": [ "### Helper functions" ] }, { "cell_type": "markdown", "id": "dda188d8-bf45-4979-a436-0bcf863ad7d7", "metadata": {}, "source": [ "The deprecated heuristics in this notebook (`ClassicEW`, `CPEW`, `NBEW`, and `OBEW`) take the location graph **L** as input and return a routed graph **G** directly. Hence, `legacy_solution()` only needs to call the legacy function and then calculate edge loads.\n", "\n", "`constructor()` works one level lower in the routing pipeline. It's input is the available-links graph **A** and its return value is the solution topology **S**. That is why `constructor_solution()` first calls `make_planar_embedding(L)` to derive the planar mesh **P** and available links **A**, then calls `constructor(A, ...)`, converts **S** to a tentative graph with `G_from_S(S, A)`, and finally uses `PathFinder(...).create_detours()` to obtain the routed graph **G** used for plotting and comparison." ] }, { "cell_type": "code", "execution_count": 3, "id": "c0dda85f-cede-4643-8478-74e1206c0b71", "metadata": {}, "outputs": [], "source": [ "def legacy_solution(fun, L, capacity, **kwargs):\n", " with warnings.catch_warnings():\n", " warnings.simplefilter('ignore', DeprecationWarning)\n", " G = fun(L, capacity=capacity, **kwargs)\n", " calcload(G)\n", " return G\n", "\n", "def constructor_solution(L, capacity, **kwargs):\n", " P, A = make_planar_embedding(L)\n", " S = constructor(A, capacity=capacity, **kwargs)\n", " G_topology = G_from_S(S, A)\n", " G = PathFinder(G_topology, planar=P, A=A).create_detours()\n", " calcload(G)\n", " return G\n", "\n", "def compare(label, legacy, constructed):\n", " return {\n", " 'case': label,\n", " 'legacy_length': round(legacy.size(weight='length')),\n", " 'constructor_length': round(constructed.size(weight='length')),\n", " 'legacy_max_load': legacy.graph['max_load'],\n", " 'constructor_max_load': constructed.graph['max_load'],\n", " }\n", "\n", "def show_pair(label, legacy, constructed):\n", " print(f'{label}: legacy')\n", " display(svgplot(legacy))\n", " print(f'{label}: constructor')\n", " display(svgplot(constructed))" ] }, { "cell_type": "markdown", "id": "502eb9be-ee46-46fb-862b-e20f3db080ae", "metadata": {}, "source": [ "### Classic Esau-Williams" ] }, { "cell_type": "code", "execution_count": 4, "id": "1006b87e-7598-44b2-920c-64783a33b3e4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'case': 'ClassicEW',\n", " 'legacy_length': 59585,\n", " 'constructor_length': 60145,\n", " 'legacy_max_load': 9,\n", " 'constructor_max_load': 9}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = locations.merkur\n", "capacity = 9\n", "\n", "G_classic = legacy_solution(ClassicEW, L, capacity)\n", "G_constructor_classic = constructor_solution(\n", " L,\n", " capacity,\n", " method='esau_williams',\n", " weigh_detours=False,\n", ")\n", "\n", "compare('ClassicEW', G_classic, G_constructor_classic)" ] }, { "cell_type": "code", "execution_count": 5, "id": "d84e40f0-2968-4561-866e-b086848cd991", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ClassicEW: legacy\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 59 585 m(+1) [-1]: 9κ = 9, T = 66" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "ClassicEW: constructor\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 60 145 m(+1) [-1]: 9κ = 9, T = 66" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_pair('ClassicEW', G_classic, G_constructor_classic)" ] }, { "cell_type": "markdown", "id": "289eff1e-3ba1-40a4-bc23-6ca4fce2335c", "metadata": {}, "source": [ "### Crossing-Preventing Esau-Williams" ] }, { "cell_type": "code", "execution_count": 6, "id": "76c702bc-4dcd-4541-b957-99a3905d5229", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'case': 'CPEW',\n", " 'legacy_length': 59922,\n", " 'constructor_length': 59902,\n", " 'legacy_max_load': 9,\n", " 'constructor_max_load': 9}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = locations.merkur\n", "capacity = 9\n", "\n", "G_cpew = legacy_solution(CPEW, L, capacity)\n", "G_constructor_cpew = constructor_solution(\n", " L,\n", " capacity,\n", " method='biased_EW',\n", " straight_feeder_route=True,\n", " weigh_detours=False,\n", ")\n", "\n", "compare('CPEW', G_cpew, G_constructor_cpew)" ] }, { "cell_type": "code", "execution_count": 7, "id": "11e6da99-9b15-4824-829d-a145666b75a8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPEW: legacy\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 59 922 m(+1) [-1]: 9κ = 9, T = 66" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "CPEW: constructor\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 59 902 m(+1) [-1]: 9κ = 9, T = 66" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_pair('CPEW', G_cpew, G_constructor_cpew)" ] }, { "cell_type": "markdown", "id": "6e97446d-fb53-4a9e-b643-223b080672f5", "metadata": {}, "source": [ "### Non-Branching Esau-Williams" ] }, { "cell_type": "code", "execution_count": 8, "id": "8e973a6b-4b72-4ca6-b833-8a148cc639be", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'case': 'NBEW',\n", " 'legacy_length': 275479,\n", " 'constructor_length': 274287,\n", " 'legacy_max_load': 9,\n", " 'constructor_max_load': 9}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = locations.sofia\n", "capacity = 9\n", "\n", "G_nbew = legacy_solution(NBEW, L, capacity)\n", "G_constructor_nbew = constructor_solution(\n", " L,\n", " capacity,\n", " method='radial_EW',\n", " straight_feeder_route=True,\n", " weigh_detours=False,\n", ")\n", "\n", "compare('NBEW', G_nbew, G_constructor_nbew)" ] }, { "cell_type": "code", "execution_count": 9, "id": "4529ec36-d766-4e6e-8e93-3d99cbb6df5e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NBEW: legacy\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 275 479 m(+5) OCP: 17κ = 9, T = 100" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "NBEW: constructor\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 274 287 m(+3) OCP: 15κ = 9, T = 100" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_pair('NBEW', G_nbew, G_constructor_nbew)" ] }, { "cell_type": "markdown", "id": "7a972411-13b3-4af1-8849-dfd82b57debf", "metadata": {}, "source": [ "### Obstacle-Bypassing Esau-Williams" ] }, { "cell_type": "code", "execution_count": 10, "id": "3f294c53-6247-4706-9f71-969b5f592943", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'case': 'OBEW rootlust',\n", " 'legacy_length': 58916,\n", " 'constructor_length': 59187,\n", " 'legacy_max_load': 6,\n", " 'constructor_max_load': 6}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = locations.borkum2\n", "capacity = 6\n", "\n", "G_obew = legacy_solution(OBEW, L, capacity, rootlust='0.6*cur_capacity/capacity')\n", "G_constructor_obew = constructor_solution(\n", " L,\n", " capacity,\n", " method='rootlust',\n", " # matching OBEW's rootlust is capacity-dependent\n", " rootlust_=(0.0, 0.6 * (capacity - 1) / capacity),\n", ")\n", "\n", "compare('OBEW rootlust', G_obew, G_constructor_obew)" ] }, { "cell_type": "code", "execution_count": 11, "id": "94e3fa82-7d23-47f9-9458-e7c61b8b3505", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OBEW rootlust: legacy\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 58 916 m(+1) OSS: 10κ = 6, T = 52" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "OBEW rootlust: constructor\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 59 187 m(+2) OSS: 11κ = 6, T = 52" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_pair('OBEW rootlust', G_obew, G_constructor_obew)" ] }, { "cell_type": "code", "execution_count": 12, "id": "2a9e282b-bb7a-4655-a794-5e64b462508e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'case': 'OBEW default',\n", " 'legacy_length': 58275,\n", " 'constructor_length': 58275,\n", " 'legacy_max_load': 6,\n", " 'constructor_max_load': 6}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G_obew_default = legacy_solution(OBEW, L, capacity)\n", "G_constructor_obew_default = constructor_solution(L, capacity, method='biased_EW')\n", "\n", "compare('OBEW default', G_obew_default, G_constructor_obew_default)" ] }, { "cell_type": "code", "execution_count": 13, "id": "7805b612-149c-4eb0-9e8d-7f10f3b429dc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OBEW default: legacy\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 58 275 m(+2) OSS: 11κ = 6, T = 52" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "OBEW default: constructor\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 58 275 m(+2) OSS: 11κ = 6, T = 52" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_pair('OBEW default', G_obew_default, G_constructor_obew_default)" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }