{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Enabling licensed solvers on Deepnote\n", "For instructions on how to run these tutorial notebooks, please see the [index](./index.ipynb).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "assert \"DEEPNOTE_PROJECT_ID\" in os.environ, \"This tutorial is meant to be run on Deepnote\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Drake's MathematicalProgram interface supports some commercial solvers that require users to provide a license file in order to activate them. This tutorial provides an example of how this can be accomplished on Deepnote; attempting to simplify the workflow but also minimize the chances of you accidentally sharing your license file.\n", "\n", "You can **duplicate this notebook**, and upload your license file, and run the code to make sure the activation works." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mosek\n", "\n", "* If you don't have one, obtain a Mosek license. If you have academic status, then you can obtain a [free personal academic license](https://www.mosek.com/products/academic-licenses/).\n", "* This cell will prompt you to upload the `mosek.lic` file from your local machine.\n", "\n", "**Please be careful to avoid publicly sharing your license file!**\n", "\n", "We upload the file to `/tmp/mosek.lic` in order to help prevent accidental sharing of your license file. It will be cleared at the end of each session.\n", "\n", "Note: If you share an active session with a collaborator with your license uploaded, they could potentially copy the file out of `/tmp` and obtain your license. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import os.path\n", "\n", "import ipywidgets as widgets # Our use requires ipywidgets >= 7.5.0\n", "from IPython.display import display\n", "\n", "if \"MOSEKLM_LICENSE_FILE\" not in os.environ:\n", " # If a mosek.lic file has already been uploaded, then simply use it here.\n", " if os.path.exists('/tmp/mosek.lic'):\n", " os.environ[\"MOSEKLM_LICENSE_FILE\"] = \"/tmp/mosek.lic\"\n", " else:\n", " uploader = widgets.FileUpload(accept='.lic', multiple=False)\n", " display(uploader)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if \"MOSEKLM_LICENSE_FILE\" not in os.environ:\n", " assert len(uploader.value.values()) > 0, \"Please upload a license file using the Upload widget above.\"\n", " with open('/tmp/mosek.lic', 'wb') as output_file:\n", " output_file.write(list(uploader.value.values())[-1]['content']) \n", " os.environ[\"MOSEKLM_LICENSE_FILE\"] = \"/tmp/mosek.lic\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can confirm that Drake believes Mosek should now be available:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pydrake.solvers import MosekSolver\n", "\n", "print(MosekSolver().enabled())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's solve a trivial semidefinite program. \n", "\n", "$$\\begin{aligned} \\min_S \\quad & \\text{Trace}(S) \\\\ \\text{subject to} \\quad & S_{1,0} = 1, \\\\ & S \\succeq 0. \\end{aligned}$$\n", "\n", "The known optimal solution is $ S = \\begin{bmatrix} 1 & 1 \\\\ 1 & 1\\end{bmatrix}.$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pydrake.solvers import MathematicalProgram, MosekSolver\n", "\n", "prog = MathematicalProgram()\n", "S = prog.NewSymmetricContinuousVariables(2, \"S\")\n", "\n", "# S ≽ 0.\n", "prog.AddPositiveSemidefiniteConstraint(S)\n", "\n", "# S(1, 0) = 1\n", "prog.AddBoundingBoxConstraint(1, 1, S[1, 0])\n", "\n", "# min Trace(S)\n", "prog.AddLinearCost(S[0,0] + S[1,1])\n", "\n", "mosek = MosekSolver()\n", "result = mosek.Solve(prog)\n", "assert result.is_success()\n", "\n", "print(result.GetSolution(S))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gurobi\n", "\n", "Gurobi is not yet available in the binary releases of Drake. We hope to enable it in the future: https://github.com/RobotLocomotion/drake/issues/10804" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Clean up\n", "\n", "For good measure, let's delete any temporary license files now." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if os.path.exists('/tmp/mosek.lic'):\n", " os.remove('/tmp/mosek.lic')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "interpreter": { "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" }, "kernelspec": { "display_name": "Python 3.9.12 64-bit", "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.9.12" }, "orig_nbformat": 2 }, "nbformat": 4, "nbformat_minor": 2 }