From 16bc1e56962d447252ad2bf260ec1937e38da942 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Tue, 14 Jan 2025 12:38:15 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(tutorials):=20Clean=20up=20&?= =?UTF-8?q?=20make=20consistent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0_transport-tutorial_platform-setup.ipynb | 20 +- tutorial/transport/1_transport-tutorial.ipynb | 120 ++- .../2_transport-tutorial_variant.ipynb | 797 ++++++++++++++++-- 3 files changed, 778 insertions(+), 159 deletions(-) diff --git a/tutorial/transport/0_transport-tutorial_platform-setup.ipynb b/tutorial/transport/0_transport-tutorial_platform-setup.ipynb index eebbd1d0..098459a2 100644 --- a/tutorial/transport/0_transport-tutorial_platform-setup.ipynb +++ b/tutorial/transport/0_transport-tutorial_platform-setup.ipynb @@ -26,7 +26,7 @@ "\n", "This tutorial consists of three Jupyter notebooks:\n", "\n", - "0. Set up an **ixmp4.Platform** to store the scenario input data and solution\n", + "0. Set up an `ixmp4.Platform` to store the scenario input data and solution\n", "1. Implement the **baseline version of the transport problem** and solve it\n", "2. Create an **alternative scenario** and solve it " ] @@ -83,7 +83,7 @@ "id": "b6209e20-9979-4f3b-b6b7-fe37a1c09366", "metadata": {}, "source": [ - "## Defining units in the platform and database\n", + "## Defining units in the `Platform` and database\n", "\n", "The **ixmp4** package requires that units are defined explicitly before adding data using them.\n", "\n", @@ -92,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "9be63ed0-aca6-44e3-a6c6-d8fdf8ec2549", "metadata": {}, "outputs": [], @@ -154,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "6c1a395d-6c8a-489c-9aa8-39d24895ca51", "metadata": {}, "outputs": [], @@ -195,19 +195,11 @@ "The prompt will ask whether you also want to delete the SQLite database file from your computer, \n", "answer `y` for a complete deletion." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9395354e-2a0a-45f1-b819-34af7d925805", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -221,7 +213,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorial/transport/1_transport-tutorial.ipynb b/tutorial/transport/1_transport-tutorial.ipynb index 72c64cdd..73dbb0c3 100644 --- a/tutorial/transport/1_transport-tutorial.ipynb +++ b/tutorial/transport/1_transport-tutorial.ipynb @@ -25,7 +25,7 @@ "\n", "This tutorial consists of three Jupyter notebooks:\n", "\n", - "0. Set up an **ixmp4.Platform** to store the scenario input data and solution\n", + "0. Set up an `ixmp4.Platform` to store the scenario input data and solution\n", "1. Implement the **baseline version of the transport problem** and solve it\n", "2. Create an **alternative scenario** and solve it " ] @@ -45,7 +45,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## The platform as a connection to the database\n", + "## The `Platform` as a connection to the database\n", "\n", "An [**ixmp4.Platform**](https://docs.ece.iiasa.ac.at/projects/ixmp4/en/latest/devs/ixmp4.core/platform.html#ixmp4.core.platform.Platform)\n", "is the connection to a database instance that can hold scenario data and relevant additional information." @@ -57,15 +57,8 @@ "metadata": {}, "outputs": [], "source": [ - "import ixmp4" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ + "import ixmp4\n", + "\n", "platform = ixmp4.Platform(\"transport-tutorial\")" ] }, @@ -75,14 +68,14 @@ "source": [ "An [**ixmp4.Run**](https://docs.ece.iiasa.ac.at/projects/ixmp4/en/latest/devs/ixmp4.core/run.html#ixmp4.core.run.Run)\n", "is an object that holds all relevant information for one quantification of a \"scenario\". \n", - "A run is identified by a *model name*, a *scenario name* and an automatically assigned *version number*.\n", + "A `Run` is identified by a *model name*, a *scenario name* and an automatically assigned *version number*.\n", "\n", - "As a first step to solve the **transport problem**, we create a new run." + "As a first step to solve the **transport problem**, we create a new `Run`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -95,13 +88,13 @@ "source": [ "## Defining the structure of the optimization problem\n", "\n", - "### The IndexSets\n", + "### The `IndexSet`s\n", "\n", - "An **IndexSet** defines a list of elements with a name. These sets can be used for \"indexed assignment\" of parameters, variables and equations. \n", - "The entries of these parameters, etc. are then validated against the elements of the linked set. \n", - "In database terms, a column of a parameter, etc. can be \"foreign-keyed\" onto an set.\n", + "An `IndexSet` defines a list of elements with a name. These sets can be used for \"indexed assignment\" of `Parameter`s, `Variable`s and `Equation`s. \n", + "The entries of these `Parameter`s, etc. are then validated against the elements of the linked set. \n", + "In database terms, a column of a `Parameter`, etc. is \"foreign-keyed\" onto a `IndexSet`.\n", "\n", - "Below, we first show the data as they would be written in the linopy tutorial." + "Below, we first show the data as they would be written in the **GAMS** tutorial." ] }, { @@ -122,7 +115,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -134,7 +127,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can display the elements of any **IndexSet** as a Python list:" + "We can display the data (a.k.a elements) of any `IndexSet` as a Python list:" ] }, { @@ -150,12 +143,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "An **IndexSet** can have a docstring as a means for documentation." + "An `IndexSet` can have a docstring as a means for documentation." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -166,14 +159,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "For simplicity, the steps of creating an **IndexSet** and assigning elements can be done in one line.\n", + "For simplicity, the steps of creating an `IndexSet` and assigning elements can be done in one line.\n", "\n", - "We illustrate this for the second index-set of the transport problem." + "We illustrate this for the second `IndexSet` of the transport problem." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -184,12 +177,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To add the docstring, we now have to explicitly get the index-set *j* and add the documentation." + "To add the docstring, we now have to explicitly get the `IndexSet` *j* and add the documentation." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -202,10 +195,10 @@ "source": [ "### Parameters of the optimization problem\n", "\n", - "A **Parameter** is a table with a number of index columns (each constrained to an **IndexSet**) as well as *units* and *values* columns.\n", + "A `Parameter` is a table with a number of index columns (each constrained to an `IndexSet`) as well as *units* and *values* columns.\n", "\n", "As a next step to solving the transport problem, we define the parameters *capacity* and *demand*.\n", - "The parameters are assigned on the indexsets *i* and *j*, respectively." + "The parameters are assigned on the `IndexSet`s *i* and *j*, respectively." ] }, { @@ -226,12 +219,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The parameter data can be assigned as a dictionary." + "The data of the `Parameter` can be assigned as a dictionary." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -250,18 +243,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Alternatively, the parameter data can be passed as a **pandas.DataFrame**." + "Alternatively, the data can be passed as a `pandas.DataFrame`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "\n", - "\n", "b = run.optimization.parameters.create(\"b\", constrained_to_indexsets=[\"j\"])\n", "b.docs = \"Demand at market j\"\n", "\n", @@ -280,7 +272,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Notice how the data has three columns but has only been linked to one **IndexSet**? That's on purpose: Every **Parameter** needs to have (the columns) *values* and *units*. The value(s) can be any number(s), but the units have to be defined a-priori in the **ixmp4.Platform**.\n", + "Notice how the data has three columns but has only been linked to one `IndexSet`? That's on purpose: Every `Parameter` needs to have (the columns) *values* and *units*. The value(s) can be any number(s), but the units have to be defined a-priori in the `ixmp4.Platform`.\n", "\n", "Here's how to access `parameter.data` to e.g. quickly confirm that *b* is set correctly:" ] @@ -315,14 +307,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "It is possible to add data to a parameter in several steps...\n", + "It is possible to add data to a `Parameter` in several steps...\n", "\n", "Here, we first define the parameter *d* and add four datapoints." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -347,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -361,7 +353,7 @@ "source": [ "
\n", "\n", - "Every time you add data, **all** columns of the parameter must be present!\n", + "Every time you add data, **all** columns of the `Parameter` must be present!\n", "\n", "
" ] @@ -372,7 +364,7 @@ "source": [ "### Scalars\n", "\n", - "Another type of input data for optimization problems is a **Scalar**. These are not linked to an **IndexSet**, but consist of only a value and a unit (and a docstring)." + "Another type of input data for optimization problems is a `Scalar`. These are not linked to an `IndexSet`, but consist of only a *value* and a *unit* (and a docstring)." ] }, { @@ -384,11 +376,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "f = run.optimization.scalars.create(name=\"f\", value=90, unit=\"dollars per case per 1000 miles\")\n", + "f = run.optimization.scalars.create(\n", + " name=\"f\", value=90, unit=\"dollars per case per 1000 miles\"\n", + ")\n", "f.docs = \"Freight\"" ] }, @@ -398,9 +392,9 @@ "source": [ "### Defining the solution structure\n", "\n", - "The solution of an optimization problem are a list of **Variable** and **Equation** objects.\n", + "The solution of an optimization problem is a list of `Variable` and `Equation` objects.\n", "\n", - "We first define the variables and equations in the **ixmp4.Run**. The values of the solution (level and marginal, mathematically speaking) are read from the **linopy** output after solving the problem." + "We first define the `Variable`s and `Equation`s in the `ixmp4.Run`. The values of the solution (level and marginal, mathematically speaking) are read from the **linopy** output after solving the problem." ] }, { @@ -421,14 +415,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Here, *supply* can only come from the canning plant in **IndexSet** *i*, while *demand* needs to be met at the markets in **IndexSet** *j*.\n", + "Here, *supply* can only come from the canning plant in `IndexSet` *i*, while *demand* needs to be met at the markets in `IndexSet` *j*.\n", "\n", "Shipment is defined from a canning plant to a market, so *x* needs to be assigned to both *i* and *j*." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -445,13 +439,13 @@ "source": [ "## Solve the scenario\n", "\n", - "In this tutorial, we solve the tutorial using the open-source solver *highs* in **linopy**. \n", + "In this tutorial, we solve the tutorial using the open-source solver [*highs*](https://github.com/ERGO-Code/HiGHS) in **linopy**. \n", "\n", - "The ``create_dantzig_model()`` function is a convenience shortcut to retrieve the data from the **ixmp4.Run**\n", - "and set up a linopy model correctly to solve the transport problem. Please see ``linopy_model.py`` for details.\n", + "The ``create_dantzig_model()`` function is a convenience shortcut to retrieve the data from the `ixmp4.Run`\n", + "and set up a **linopy** model correctly to solve the transport problem. Please see ``linopy_model.py`` for details.\n", "\n", "The solution of the transport problem is stored with the model object automatically.\n", - "The function ``store_dantzig_solution()`` reads the solution and stores it in the respective **Variable** and **Equation** objects of the **ixmp4.Run**." + "The function ``store_dantzig_solution()`` reads the solution and stores it in the respective `Variable` and `Equation` objects of the `ixmp4.Run`." ] }, { @@ -465,7 +459,6 @@ " read_dantzig_solution,\n", ")\n", "\n", - "\n", "linopy_model = create_dantzig_model(run=run)\n", "linopy_model.solve(\"highs\")\n", "read_dantzig_solution(model=linopy_model, run=run)" @@ -511,7 +504,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The levels and marginals of the **Equation** show the shipped quantities and shadow prices (\"dual variables\") of the least-cost solution." + "The levels and marginals of the `Equation`s show the shipped quantities and shadow prices (\"dual variables\") of the least-cost solution." ] }, { @@ -536,36 +529,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Setting a default version of a run\n", + "## Setting a default version of a `Run`\n", "\n", - "The key benefit of **ixmp4** is handling a large number of scenarios - aka **ixmp4.Run** objects - in a version-controlled database.\n", - "Each run is identified by a *model name*, a *scenario name* and an automatically assigned *version number*.\n", + "The key benefit of **ixmp4** is handling a large number of scenarios - aka `ixmp4.Run` objects - in a version-controlled database.\n", + "Each `Run` is identified by a *model name*, a *scenario name* and an automatically assigned *version number*.\n", "\n", - "For every model-scenario combination, we can assign one run as the *default version*.\n", + "For every model-scenario combination, we can assign one `Run` as the *default version*.\n", "This allows to keep previous versions in the database (for easy reference and comparison) but have a well-defined approach to get the \"right\" version (e.g., the latest version of a scenario)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "run.set_as_default()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -579,7 +565,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorial/transport/2_transport-tutorial_variant.ipynb b/tutorial/transport/2_transport-tutorial_variant.ipynb index e8b1b2d7..fa8f87bc 100644 --- a/tutorial/transport/2_transport-tutorial_variant.ipynb +++ b/tutorial/transport/2_transport-tutorial_variant.ipynb @@ -25,7 +25,7 @@ "\n", "This tutorial consists of three Jupyter notebooks:\n", "\n", - "0. Set up an **ixmp4.Platform** to store the scenario input data and solution\n", + "0. Set up an `ixmp4.Platform` to store the scenario input data and solution\n", "1. Implement the **baseline version of the transport problem** and solve it\n", "2. Create an **alternative scenario** and solve it " ] @@ -45,7 +45,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## The platform as a connection to the database\n", + "## The `Platform` as a connection to the database\n", "\n", "An [**ixmp4.Platform**](https://docs.ece.iiasa.ac.at/projects/ixmp4/en/latest/devs/ixmp4.core/platform.html#ixmp4.core.platform.Platform)\n", "is the connection to a database instance that can hold scenario data and relevant additional information." @@ -53,20 +53,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[INFO] 11:36:49 - ixmp4.conf.auth: Connecting to service anonymously and without credentials.\n", + "[INFO] 11:36:49 - ixmp4.data.backend.db: Creating database engine for platform 'transport-tutorial'.\n" + ] + } + ], "source": [ "import ixmp4\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ + "\n", "platform = ixmp4.Platform(\"transport-tutorial\")" ] }, @@ -75,14 +76,63 @@ "metadata": {}, "source": [ "As a first step, we list all scenarios (aka [**ixmp4.Run**](https://docs.ece.iiasa.ac.at/projects/ixmp4/en/latest/devs/ixmp4.core/run.html#ixmp4.core.run.Run) instances)\n", - "available in the platform connected to the database instance." + "available in the `Platform` connected to the database instance." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelscenarioversionis_default
0transport problemstandard1True
\n", + "
" + ], + "text/plain": [ + " model scenario version is_default\n", + "0 transport problem standard 1 True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "platform.runs.tabulate()" ] @@ -103,14 +153,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Retrieve a run from the platform\n", + "## Retrieve a `Run` from the `Platform`\n", "\n", - "As a first step in this notebook, you can load the **ixmp4.Run** that you created in Notebook 1." + "As a first step in this notebook, you can load the `ixmp4.Run` that you created in [Notebook 1](1_transport-tutorial.ipynb)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -126,9 +176,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "run.version" ] @@ -137,15 +198,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You can check that the solution from Notebook 1 was indeed saved by inspecting an **ixmp4.Variable**. \n", + "You can check that the solution from [Notebook 1](1_transport-tutorial.ipynb) was indeed saved by inspecting an `ixmp4.Variable`. \n", "The `data` of any optimization object is stored internally as a dictionary." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'levels': [151.875], 'marginals': [-0.0]}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "run.optimization.variables.get(\"z\").data" ] @@ -154,27 +226,101 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "For instances of a **Variable** or a **Parameter** that have multiple dimensions,\n", + "For instances of a `Variable` or a `Parameter` that have multiple dimensions,\n", "you can use **pandas** for filtering and inspecting the data.\n", "\n", - "The following cell shows the data for a using the distance parameter *d* and cast the `Parameter.data` to a **pandas.DataFrame**." + "The following cell shows how to retrieve the distance parameter *d* and cast the `Parameter.data` to a `pandas.DataFrame`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ + "import pandas as pd\n", + "\n", "d = run.optimization.parameters.get(\"d\")\n", "distance = pd.DataFrame(d.data)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**pandas** enables easy and powerful filtering, e.g. showing only the distances for connections from Seattle:" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ijvaluesunits
3seattlechicago1.71000 miles
4seattlenew-york2.51000 miles
5seattletopeka1.81000 miles
\n", + "
" + ], + "text/plain": [ + " i j values units\n", + "3 seattle chicago 1.7 1000 miles\n", + "4 seattle new-york 2.5 1000 miles\n", + "5 seattle topeka 1.8 1000 miles" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "distance[distance[\"i\"] == \"seattle\"]" ] @@ -188,9 +334,66 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ijvaluesunits
3seattlechicago1.71000 miles
5seattletopeka1.81000 miles
\n", + "
" + ], + "text/plain": [ + " i j values units\n", + "3 seattle chicago 1.7 1000 miles\n", + "5 seattle topeka 1.8 1000 miles" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "distance.loc[(distance[\"i\"] == \"seattle\") & (distance[\"j\"].isin([\"chicago\", \"topeka\"]))]" ] @@ -218,7 +421,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "metadata": {}, "outputs": [], "source": [ @@ -234,9 +437,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'transport problem'" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "run_detroit.model.name" ] @@ -246,12 +460,12 @@ "metadata": {}, "source": [ "We now modify the structure and parameters of the *detroit* scenario.\n", - "First, we reduce the demand in *chicago* to ensure a feasible problem.." + "First, we reduce the demand in *chicago* to ensure a feasible problem." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": {}, "outputs": [], "source": [ @@ -269,7 +483,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 49, "metadata": {}, "outputs": [], "source": [ @@ -282,7 +496,7 @@ " \"i\": [\"seattle\", \"san-diego\"],\n", " \"j\": [\"detroit\", \"detroit\"],\n", " \"values\": [1.7, 1.9],\n", - " \"units\": [\"km\", \"km\"],\n", + " \"units\": [\"1000 miles\", \"1000 miles\"],\n", " }\n", ")" ] @@ -294,21 +508,49 @@ "### Solve the new scenario\n", "\n", "Now, we create a **linopy** model, solve it, and read the solution to store it\n", - "in the respective **Variable** and **Equation** objects of the **ixmp4.Run**." + "in the respective `Variable` and `Equation` objects of the `ixmp4.Run`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running HiGHS 1.9.0 (git hash: fa40bdf): Copyright (c) 2024 HiGHS under MIT licence terms\n", + "Coefficient ranges:\n", + " Matrix [1e+00, 1e+00]\n", + " Cost [1e-01, 2e-01]\n", + " Bound [0e+00, 0e+00]\n", + " RHS [2e+02, 6e+02]\n", + "Presolving model\n", + "6 rows, 8 cols, 16 nonzeros 0s\n", + "6 rows, 8 cols, 16 nonzeros 0s\n", + "Presolve : Reductions: rows 6(-0); columns 8(-0); elements 16(-0) - Not reduced\n", + "Problem not reduced by presolve: solving the LP\n", + "Using EKK dual simplex solver - serial\n", + " Iteration Objective Infeasibilities num(sum)\n", + " 0 0.0000000000e+00 Pr: 4(950) 0s\n", + " 5 1.6132500000e+02 Pr: 0(0) 0s\n", + "Model name : linopy-problem-46ex2ggk\n", + "Model status : Optimal\n", + "Simplex iterations: 5\n", + "Objective value : 1.6132500000e+02\n", + "Relative P-D gap : 0.0000000000e+00\n", + "HiGHS run time : 0.00\n", + "Writing the solution to /tmp/linopy-solve-zx4bkwxw.sol\n" + ] + } + ], "source": [ "from tutorial.transport.dantzig_model_linopy import (\n", " create_dantzig_model,\n", " read_dantzig_solution,\n", ")\n", "\n", - "\n", "linopy_model_detroit = create_dantzig_model(run=run_detroit)\n", "linopy_model_detroit.solve(\"highs\")\n", "read_dantzig_solution(model=linopy_model_detroit, run=run_detroit)" @@ -320,12 +562,12 @@ "source": [ "## Setting a default version of the scenario\n", "\n", - "As in Notebook 1, we set the *detroit* scenario as the default version so that we can easily retrieve it later." + "As in [Notebook 1](1_transport-tutorial.ipynb), we set the *detroit* scenario as the default version so that we can easily retrieve it later." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "metadata": {}, "outputs": [], "source": [ @@ -338,33 +580,55 @@ "source": [ "## Display and analyze the results\n", "\n", - "We can now compare the *standard* instance of the *transport problem* and the *detroit* scenario.\n", + "We can now compare the *standard* instance of the **transport problem** and the *detroit* scenario.\n", "\n", - "The next two cells show the objective values of the two runs." + "The next two cells show the objective values of the two `Run`s." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, "metadata": { "jupyter": { "name": "scen-z" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[151.875]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "run.optimization.variables.get(\"z\").levels" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "metadata": { "jupyter": { "name": "scen-detroit-z" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[161.325]" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "run_detroit.optimization.variables.get(\"z\").levels" ] @@ -375,34 +639,296 @@ "source": [ "You see that the *detroit* scenario has higher total cost.\n", "\n", - "The next two cells compare the optimal assignment of shipments from plants to markets in the two runs." + "The next two cells compare the optimal assignment of shipments from plants to markets in the two `Run`s." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ijlevelsmarginals
0seattlenew-york0.0-0.0
1seattlechicago75.0-0.0
2seattletopeka275.0-0.0
3san-diegonew-york325.0-0.0
4san-diegochicago225.0-0.0
5san-diegotopeka0.0-0.0
\n", + "
" + ], + "text/plain": [ + " i j levels marginals\n", + "0 seattle new-york 0.0 -0.0\n", + "1 seattle chicago 75.0 -0.0\n", + "2 seattle topeka 275.0 -0.0\n", + "3 san-diego new-york 325.0 -0.0\n", + "4 san-diego chicago 225.0 -0.0\n", + "5 san-diego topeka 0.0 -0.0" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "pd.DataFrame(run.optimization.variables.get(\"x\").data)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ijlevelsmarginals
0san-diegochicago150.0-0.0
1san-diegodetroit0.0-0.0
2san-diegonew-york200.0-0.0
3san-diegotopeka250.0-0.0
4seattlechicago0.0-0.0
5seattledetroit275.0-0.0
6seattlenew-york0.0-0.0
7seattletopeka75.0-0.0
\n", + "
" + ], + "text/plain": [ + " i j levels marginals\n", + "0 san-diego chicago 150.0 -0.0\n", + "1 san-diego detroit 0.0 -0.0\n", + "2 san-diego new-york 200.0 -0.0\n", + "3 san-diego topeka 250.0 -0.0\n", + "4 seattle chicago 0.0 -0.0\n", + "5 seattle detroit 275.0 -0.0\n", + "6 seattle new-york 0.0 -0.0\n", + "7 seattle topeka 75.0 -0.0" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "pd.DataFrame(run_detroit.optimization.variables.get(\"x\").data)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
jlevelsmarginals
0chicago150.00.153
1detroit275.00.126
2new-york200.00.153
3topeka325.00.225
\n", + "
" + ], + "text/plain": [ + " j levels marginals\n", + "0 chicago 150.0 0.153\n", + "1 detroit 275.0 0.126\n", + "2 new-york 200.0 0.153\n", + "3 topeka 325.0 0.225" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "run_detroit.optimization.equations.get(\"demand\").data" + "pd.DataFrame(run_detroit.optimization.equations.get(\"demand\").data)" ] }, { @@ -411,16 +937,73 @@ "source": [ "## Scenario version management\n", "\n", - "As above, you can now list all scenarios available in the database instance to which the **ixmp4.Platform** is connected.\n", + "As above, you can now list all scenarios available in the database instance to which the `ixmp4.Platform` is connected.\n", "\n", "You should now see (at least) two scenarios." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 57, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelscenarioversionis_default
0transport problemstandard1True
1transport problemdetroit2True
\n", + "
" + ], + "text/plain": [ + " model scenario version is_default\n", + "0 transport problem standard 1 True\n", + "1 transport problem detroit 2 True" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "platform.runs.tabulate()" ] @@ -431,15 +1014,15 @@ "source": [ "When developing scenarios, we often make minor variations to numerous scenarios, and changing the *scenario name* every time is not practical.\n", "\n", - "The **ixmp4** package provides a more efficient approach to scenario version management: Every time that you *create* a new run or *clone* an existing run and the *model-scenario-name* combination already exists, a new *version* will be created.\n", + "The **ixmp4** package provides a more efficient approach to scenario version management: Every time that you `create()` a new `Run` or `clone()` an existing `Run` and the *model-scenario-name* combination already exists, a new *version* will be created.\n", "\n", - "You can get a specific *version* by including the version number in the call to get an **ixmp4.Run** like\n", + "You can get a specific *version* by including the version number in the call to get an `ixmp4.Run` like\n", "\n", "```python\n", "platforms.runs.get(model, scenario, version)\n", "```\n", "\n", - "You also can assign one of the versions as *default*, so that this run will be retrieved when you call\n", + "You also can assign one of the versions as *default*, so that this `Run` will be retrieved when you call\n", "\n", "```python\n", "platforms.runs.get(model, scenario)\n", @@ -447,16 +1030,81 @@ "\n", "without a version number.\n", "\n", - "All versions will be kept in the database and are accessible via the **ixmp4.Platform**.\n", + "All versions will be kept in the database and are accessible via the `ixmp4.Platform`.\n", "\n", - "If you have run this tutorial multiple times, you can tabulate all runs - including the non-default versions - as illustrated below." + "If you have run this tutorial multiple times, you can tabulate all `Run`s - including the non-default versions - as illustrated below." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 58, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelscenarioversionis_default
0transport problemstandard1True
1transport problemdetroit1False
2transport problemdetroit2True
\n", + "
" + ], + "text/plain": [ + " model scenario version is_default\n", + "0 transport problem standard 1 True\n", + "1 transport problem detroit 1 False\n", + "2 transport problem detroit 2 True" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "platform.runs.tabulate(default_only=False)" ] @@ -474,21 +1122,14 @@ "ixmp4 platforms remove transport-tutorial\n", "```\n", "\n", - "The prompt will ask whether you also want to delete the SQLite database file from your computer." + "The prompt will ask whether you also want to delete the SQLite database file from your computer, answer `y` for a complete deletion." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -502,7 +1143,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.12.3" } }, "nbformat": 4,