diff --git a/resources/examples/bin-packing.ipynb b/resources/examples/bin-packing.ipynb index 119b0d2..c5595c7 100644 --- a/resources/examples/bin-packing.ipynb +++ b/resources/examples/bin-packing.ipynb @@ -202,7 +202,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/resources/examples/consecutive-shift-scheduling.ipynb b/resources/examples/consecutive-shift-scheduling.ipynb index 7430a2b..faf8cee 100644 --- a/resources/examples/consecutive-shift-scheduling.ipynb +++ b/resources/examples/consecutive-shift-scheduling.ipynb @@ -8,7 +8,7 @@ "# Consecutive shift scheduling\n", "\n", "
\n", - " ⓘ The code in this notebook requires a valid Opvious account. You may execute it from your browser here if you update the client's creation below to use an explicit API token corresponding to your account.\n", + " ⓘ The code in this notebook requires a valid Opvious license. You may execute it from your browser at this URL if you update the client's creation below to point to your licensed API.\n", "
" ] }, @@ -210,7 +210,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/resources/guides/uploading-a-model.ipynb b/resources/guides/uploading-a-model.ipynb deleted file mode 100644 index cd8859f..0000000 --- a/resources/guides/uploading-a-model.ipynb +++ /dev/null @@ -1,266 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "b1e45002-aa7d-44f8-ae0e-aeb33d2e9eab", - "metadata": {}, - "source": [ - "## Uploading a model\n", - "\n", - "
\n", - " ⓘ The code in this notebook can be executed directly from your browser. You will need an Opvious account.\n", - "
\n", - "\n", - "In this notebook we show how to upload a model such that it can be solved without access to the original specification. This approach is useful in automated environments and production, particularly in combination with version tags." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "dd3e2c07-1f43-4ad1-809b-badc3f7c8a66", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install opvious" - ] - }, - { - "cell_type": "markdown", - "id": "a8167f57-87d4-4f88-99d7-837f51a5e7af", - "metadata": {}, - "source": [ - "## Formulation\n", - "\n", - "We will use the [bin-packing problem](https://www.opvious.io/notebooks/retro/notebooks/?path=examples/bin-packing.ipynb) as example and use the same formulation." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "de9a68f2-7e9a-4def-b479-6c5f32981024", - "metadata": {}, - "outputs": [], - "source": [ - "import opvious.modeling as om\n", - "\n", - "class BinPacking(om.Model):\n", - " \"\"\"Bin-packing MIP formulation\"\"\"\n", - " \n", - " items = om.Dimension() # Set of items to be put into bins\n", - " weight = om.Parameter.non_negative(items) # Weight of each item\n", - " bins = om.interval(1, om.size(items), name=\"B\") # Set of bins\n", - " max_weight = om.Parameter.non_negative() # Maximum weight allowed in a bin\n", - " assigned = om.Variable.indicator(bins, items, qualifiers=['bins']) # 1 if an item is assigned to a given bin, 0 otherwise\n", - " used = om.Variable.indicator(bins) # 1 if a bin is used, 0 otherwise\n", - "\n", - " @om.constraint\n", - " def each_item_is_assigned_once(self):\n", - " \"\"\"Constrains each item to be assigned to exactly one bin\"\"\"\n", - " for i in self.items:\n", - " yield om.total(self.assigned(b, i) for b in self.bins) == 1\n", - "\n", - " @om.constraint\n", - " def bin_weights_are_below_max(self):\n", - " \"\"\"Constrains each bin's total weight to be below the maximum allowed\"\"\"\n", - " for b in self.bins:\n", - " bin_weight = om.total(self.weight(i) * self.assigned(b, i) for i in self.items)\n", - " yield bin_weight <= self.used(b) * self.max_weight()\n", - "\n", - " @om.objective\n", - " def minimize_bins_used(self):\n", - " \"\"\"Minimizes the total number of bins with at least one item\"\"\"\n", - " return om.total(self.used(b) for b in self.bins)\n", - "\n", - "model = BinPacking()" - ] - }, - { - "cell_type": "markdown", - "id": "9270a9d3-acbb-4574-992b-35260c7f39a0", - "metadata": {}, - "source": [ - "## Application\n", - "\n", - "Instead of optimizing directly from the model as in the original notebook, we will first upload it. This requires two main pieces:\n", - "\n", - "+ An API token, from which to generate an authenticated client.\n", - "+ A name for the uploaded formulation, which later be used to refer to it when optimizing." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "699cb44d-5fb9-4f3c-a737-104a6e3af89a", - "metadata": {}, - "outputs": [], - "source": [ - "import opvious\n", - "\n", - "client = opvious.Client.from_environment(default_endpoint=opvious.DEMO_ENDPOINT)\n", - "\n", - "FORMULATION_NAME = \"bin-packing\"\n", - "\n", - "async def upload_model(version_tag=None):\n", - " \"\"\"Saves the bin-packing model so that it can be solved just from the formulation name\n", - "\n", - " Args:\n", - " version_tag: Optional versioning tag used to target specific model versions.\n", - " \"\"\"\n", - " await client.register_specification(model.specification(), FORMULATION_NAME, tag_names=[version_tag] if version_tag else None)\n", - "\n", - "await upload_model()" - ] - }, - { - "cell_type": "markdown", - "id": "2df2c83c-946a-45a8-b61a-094e47201268", - "metadata": {}, - "source": [ - "We can now get solutions just with the formulation name. The code is very similar to the one in the original bin-packing example, we simply replaced the inline specification with a `FormulationSpecification`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "308e053a-b931-45a4-adda-c37dec3bdf25", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": "[('heavy',), ('light', 'medium')]" - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "async def optimal_assignment(bin_max_weight, item_weights, version_tag=None):\n", - " \"\"\"Returns a grouping of items which minimizes the number of bins used\n", - " \n", - " Args:\n", - " bin_max_weight: The maximum allowable total weight for all items assigned to a given bin\n", - " item_weights: Mapping from item name to its (non-negative) weight\n", - " version_tag: Model version tag\n", - " \"\"\"\n", - " problem = opvious.Problem(\n", - " specification=opvious.FormulationSpecification(FORMULATION_NAME), # Note the formulation reference\n", - " parameters={'weight': item_weights, 'maxWeight': bin_max_weight},\n", - " )\n", - " solution = await client.solve(problem)\n", - " assignment = solution.outputs.variable('assigned')\n", - " return list(assignment.reset_index().groupby('bins')['items'].agg(tuple))\n", - "\n", - "await optimal_assignment(15, {\n", - " 'light': 5,\n", - " 'medium': 10,\n", - " 'heavy': 15,\n", - "})" - ] - }, - { - "cell_type": "markdown", - "id": "ddb53774-b219-4a22-8d80-8f85224bc6e5", - "metadata": {}, - "source": [ - "We can also make requests without the SDK: under the hood everything goes through the same API (see its OpenAPI specification [here](https://api.try.opvious.io/openapi.yaml)). To show how, we implement below a function which returns the minimum number of bins needed to fit the input items (our model's objective value) using the popular `requests` library." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "0b6b5530-1c0d-42e8-b985-7a7c5d5d8f35", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install requests" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "171d4c7e-5b5e-4d02-8dc0-b4165c600da8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": "2" - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "import requests\n", - "\n", - "_token = os.environ.get('OPVIOUS_TOKEN')\n", - "\n", - "def minimum_bin_count(bin_max_weight, item_weights, version_tag='latest'):\n", - " \"\"\"Returns the minimum number of bins needed to fit the input items\n", - "\n", - " Args:\n", - " bin_max_weight: The maximum allowable total weight for all items assigned to a given bin\n", - " item_weights: Mapping from item name to its (non-negative) weight\n", - " version_tag: Model version tag\n", - " \"\"\"\n", - " response = requests.post(\n", - " url=f'{client.executor.endpoint}/solve',\n", - " headers={\n", - " 'accept': 'application/json',\n", - " 'authorization': f'Bearer {_token}',\n", - " },\n", - " json={\n", - " 'problem': {\n", - " 'formulation': {'name': FORMULATION_NAME, 'specificationTagName': version_tag},\n", - " 'inputs': {\n", - " 'parameters': [\n", - " {'label': 'maxWeight', 'entries': [{'key': [], 'value': bin_max_weight}]},\n", - " {'label': 'weight', 'entries': [{'key': k, 'value': v} for k, v in item_weights.items()]},\n", - " ]\n", - " }\n", - " }\n", - " }\n", - " )\n", - " return response.json()['outcome']['objectiveValue']\n", - "\n", - "if _token:\n", - " minimum_bin_count(15, {\n", - " 'light': 5,\n", - " 'medium': 10,\n", - " 'heavy': 15,\n", - " })" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "dc047f77-7b0f-466e-87e1-a9c361a76f0e", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.12.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/resources/guides/welcome.ipynb b/resources/guides/welcome.ipynb index b3b8b70..5a1720f 100644 --- a/resources/guides/welcome.ipynb +++ b/resources/guides/welcome.ipynb @@ -10,7 +10,7 @@ "In this notebook we introduce [Opvious](https://www.opvious.io), a _batteries-included optimization platform_, by walking through an end-to-end optimization example.\n", "\n", "
\n", - " ⓘ This example can be run directly from your browser when accessed via its opvious.io/notebooks URL. No Opvious account required.\n", + " ⓘ This example can be run directly from your browser when accessed via its opvious.io/notebooks URL.\n", "
\n", "\n", "Let's imagine that we are tasked with allocating a budget between various projects. We are also given an expected cost and value for each project. Our goal is to __pick projects__ which __maximize total value__ while keeping __total cost within the budget__. It turns out that our task can be formulated naturally as an [integer programming problem](https://en.wikipedia.org/wiki/Integer_programming) (it is actually an instance of the [knapsack problem](https://en.wikipedia.org/wiki/Knapsack_problem)) which--unlike heuristics--will be guaranteed to give us an optimal allocation.\n", @@ -239,7 +239,6 @@ "## Next steps\n", "\n", "+ Browse our other interactive [guides and examples](https://www.opvious.io/notebooks/retro)\n", - "+ Create a (free) account via the [Optimization Hub](https://hub.cloud.opvious.io) to solve larger problems\n", "+ Try the platform out locally with a [self-hosted API server](https://hub.docker.com/r/opvious/api-server)" ] }, @@ -268,7 +267,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.12.7" } }, "nbformat": 4,