{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quick Start\n", "\n", "This guide will walk you through the initial steps to leverage minto. In this section, we will cover four main steps from setting up minto to handling experimental data.\n", "\n", "- How to install minto\n", "- Recording experimental data\n", "- Viewing recorded experimental data in a table\n", "- Saving and loading experimental data\n", "\n", "## Installation\n", "\n", "```bash\n", "pip install minto\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Record Experimental Data\n", "\n", "With `minto` you can easily record various data generated during experiments. \n", "In the following example, we will conduct numerical experiments on the time limit dependency of MIP solvers using PySCIPOpt, which is supported by OMMX.\n", "`minto` natively supports OMMX Message, allowing us to smoothly perform numerical experiments through OMMX.\n", "\n", "Let's give it a try." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import minto\n", "import ommx_pyscipopt_adapter as scip_ad\n", "from ommx.dataset import miplib2017" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we will pick up an instance from miplib2017 as a benchmark target. We can easily obtain miplib2017 instances using ommx.dataset." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "instance_name = \"reblock115\"\n", "instance = miplib2017(instance_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the `ommx_pyscipopt_adapter`, we convert ommx.v1.Instance to PySCIPOpt's Model and conduct experiments by varying the limits/time parameter.\n", "\n", "The ommx instance and solution can be saved using MINTO's `.log_*` methods. Since we're using a single instance that doesn't change throughout this numerical experiment, we store it in the `experiment` space outside the with block. \n", "Solutions are saved within the with block (in the `run` space) since they vary for each time limit." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "timelimit_list = [0.1, 0.5, 1, 2]\n", "\n", "# When auto_saving is True, data is saved automatically whenever Experiment.log_* methods are called.\n", "# Since data is saved progressively, even if an error occurs midway, the data up to that point won't be lost.\n", "experiment = minto.Experiment(\n", " name='scip_exp',\n", " auto_saving=True\n", ")\n", "\n", "experiment.log_instance(instance_name, instance)\n", "adapter = scip_ad.OMMXPySCIPOptAdapter(instance)\n", "scip_model = adapter.solver_input\n", "\n", "for timelimit in timelimit_list:\n", " with experiment.run():\n", " experiment.log_parameter(\"timelimit\", timelimit)\n", "\n", " # Solve by SCIP\n", " scip_model.setParam(\"limits/time\", timelimit)\n", " scip_model.optimize()\n", " solution = adapter.decode(scip_model)\n", "\n", " experiment.log_solution(\"scip\", solution)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When converting ommx.Solution to pandas.DataFrame using the `.get_run_table` method, only the main information of the solution is displayed. If you want to access the actual solution objects, you can reference them from `experiment.dataspaces.run_datastores[run_id].solutions`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
solution_scipparametermetadata
objectivefeasibleoptimalityrelaxationstartnametimelimitrun_idelapsed_time
run_id
00.000000e+00True00Nonescip0.100.119688
1-3.027709e+07True00Nonescip0.510.399354
2-3.027709e+07True00Nonescip1.020.507941
3-3.027709e+07True00Nonescip2.031.009734
\n", "
" ], "text/plain": [ " solution_scip parameter \\\n", " objective feasible optimality relaxation start name timelimit \n", "run_id \n", "0 0.000000e+00 True 0 0 None scip 0.1 \n", "1 -3.027709e+07 True 0 0 None scip 0.5 \n", "2 -3.027709e+07 True 0 0 None scip 1.0 \n", "3 -3.027709e+07 True 0 0 None scip 2.0 \n", "\n", " metadata \n", " run_id elapsed_time \n", "run_id \n", "0 0 0.119688 \n", "1 1 0.399354 \n", "2 2 0.507941 \n", "3 3 1.009734 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "runs_table = experiment.get_run_table()\n", "runs_table" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "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AdsvLuukc3Xa+XKu9uWk8+VcPUPFGxWC2rVrJ76+DfcEokboLNQvr0OHDuIU6g/R7i88J56r086Xc7UvJ50v53r+GqsJcqOzNAAAcCyCEAAAcCyCELSgoCCZPXu2vrU7J52r086Xc7UvJ50v5+pddJYGAACORY0QAABwLIIQAABwLIIQAABwLIKQjS1YsEA6d+4swcHBMmTIENm8eXODx77++usycuRIadOmjd7GjRt3xvGTJk3Sk0rW3iZMmCBWO9eFCxeecR7qebWprnOPP/64JCQkSEhIiP59pKWlidXONTk5+YxzVduVV15p+uu6du1aufrqq/VkaKpMS5cuPetzUlJSZNCgQbrjZbdu3fS1Pp/fn5nP98MPP5Sf//znEhsbq+dfGTZsmHz66ad1jnniiSfOuLa9evUSq52ruq71/R1nZmaa/tqe67nW93pUW58+fUx/XefOnSsXX3yxnoC4bdu2cu2110pqaupZn7d48WJdfnXd+vXrJ//+97+9+n5MELKpDz74QB588EHdG3/btm0yYMAAGT9+vGRlZTX4RnPzzTfL6tWrZePGjXqmz8suu0wOHTpU5zj1AXnkyJGa7b333hOrnauiPjhqn8ePP/5Y5/H58+fL888/L6+88ops2rRJWrVqpb9naWmpWOlc1Ydl7fP87rvvxM/PTyZOnGj661pcXKzPT324NcXevXt1wBszZoxs375d7r//fvmf//mfOuGgOX8rZj1f9QGrgpD60Ni6das+b/WB+/XXX9c5Tn2A1r62X3zxhVjtXN3Uh2rtc1Eftma/tud6rn/5y1/qnKOacTkqKuqM16wZr+uaNWtk6tSp8uWXX8qKFSukoqJCf46o30FDNmzYoD97Jk+erP92VXhSm3qv8tr7sRo1Bvu55JJLXFOnTq35uqqqytWuXTvX3Llzm/T8yspKV1hYmOutt96q2ferX/3Kdc0117isfq5vvvmmKyIiosHvV11d7YqPj3c9/fTTNfvy8/NdQUFBrvfee89l5ev63HPP6etaVFRk+utam3qrWrJkSaPH/OY3v3H16dOnzr4bb7zRNX78eI/9/sx0vvXp3bu3a86cOTVfz5492zVgwACXmTXlXFevXq2PO3bsWIPHWOHaNue6quN9fHxc+/bts9R1VbKysvQ5r1mzxtWQG264wXXllVfW2TdkyBDXPffc47X3Y2qEbKi8vFz/h6iqD2svFaK+VrU9TVFSUqLTvPpP5PSaI/VfWM+ePWXKlCmSm5srVjzXoqIi6dSpk675uuaaa+T777+vU7Ogqtxrf081Tbuqam/q78+s1/X//u//5KabbtL/UZn5ujaH+h3U/t0o6r9G9+/GE78/s6+LqNZVOv01q5oQVLNM165d5dZbb5X9+/eLVV144YW6eUTVhK1fv75mv52vrXrNqvNQ71dWu64FBQX69vS/yXN53Xrj/ZggZEM5OTlSVVUlcXFxdfarr09vU2/II488ol9ktf/4VPPJokWLZOXKlTJv3jxdDXr55Zfrn2Wlc1Uf9n/961/lo48+kr/97W/6A2T48OFy8OBB/bj7eefz+zPjdVX9JVR1s2ouqs2M17U51O+gvt+NWtTxxIkTHnldmNkzzzyjA/4NN9xQs099WKh+UsuXL5eXX35Zf6iovoAqMFmJCj+qWeSf//yn3tQ/MKr/m2oCU+x6bdWC3//5z3/OeM1a4bpWV1fr5ulLL71U+vbte86vW/d188b7MYuu4gx//OMf5f3339e1BLU7EauaBDfVoa1///6SlJSkjxs7dqxYhepUqjY3FYIuuOACefXVV+V3v/ud2JX6z1Jdt0suuaTOfrtcVyd79913Zc6cOTrc1+43owKtm7qu6gNU1Sz8/e9/130yrEL986K22q/ZjIwMee655+Ttt98Wu3rrrbckMjJS95mpzQrXderUqfofLzP0XTobaoRsKCYmRneIPXr0aJ396uv4+Piz/lepgtBnn32mX2CNUVWy6melp6eLFc/VLSAgQAYOHFhzHu7nnc/3NNu5qs6KKtw25U3SDNe1OdTvoL7fjeoYr0aaeOJvxYzUdVU1BupD8PQmhtOpD9UePXpY7trWRwV693nY8dqqLkWq5vr222+XwMBAS13XadOmybJly/Tgmw4dOjTrdeu+bt54PyYI2ZB60QwePFg3ddSuplRf164JOZ3qma9qRFR160UXXXTWn6OaklRfElVtbbVzrU1VqX/77bc159GlSxf9Aqv9PVXzihqt0NTvabZzVcNTy8rK5LbbbrPEdW0O9Tuo/btR1MgV9+/GE38rZqNG99155536tvaUCA1RTWeqJsVq17Y+amSg+zzseG1VE7UKNk3558Us19XlcukQtGTJElm1apV+Lz3f161X3o890uUapvP+++/rXvULFy50/fDDD667777bFRkZ6crMzNSP33777a4ZM2bUHP/HP/7RFRgY6PrHP/7hOnLkSM12/Phx/bi6feihh1wbN2507d271/X555+7Bg0a5OrevburtLTUZaVzVaNqPv30U1dGRoZr69atrptuuskVHBzs+v777+v8PtT3+Oijj1w7duzQo6q6dOniOnHihMtK5+o2YsQIPYLqdGa+rqpsX3/9td7UW9Wf/vQnff/HH3/Uj6vzVOfrtmfPHldoaKjr4Ycfdu3cudO1YMECl5+fn2v58uVN/v1Z6Xzfeecdl7+/vz7P2q9ZNaLGbfr06a6UlBR9bdevX+8aN26cKyYmRo/msdK5qtGOS5cudaWlpbm+/fZb169//WuXr6+v/ns1+7U913N1u+222/ToqfqY9bpOmTJFj8hVZav9N1lSUlJzzOnvUar86u/4mWee0a9bNSIuICBAX2dvvR8ThGzshRdecHXs2FEHHDW09Msvv6x5bPTo0XrYtFunTp30i/T0Tf1RKuoP+bLLLnPFxsbqP1J1/F133WX4m0xzzvX++++vOTYuLs51xRVXuLZt21bn+6khm4899ph+XL25jh071pWamuqy2rkqu3bt0tfys88+O+N7mfm6uodMn765z0/dqvM9/TkXXnih/t107dpVT5VwLr8/K52vut/Y8YoKvwkJCfpc27dvr79OT093We1c582b50pKStL/sERFRbmSk5Ndq1atssS1bc7fsQqzISEhrtdee63e72nW6yr1nKfaar8O63uP+vvf/+7q0aOHPh81Bca//vUvr74fs/o8AABwLPoIAQAAxyIIAQAAxyIIAQAAxyIIAQAAxyIIAQAAxyIIAQAAxyIIAQAAxyIIAQAAxyIIATClSZMmnbHqtjcsXLhQL2Lp9sQTT8iFF154Xt9z37594uPjo9fHAmAu/kYXAIDzqFDQmNmzZ8tf/vIXvYij0R566CG57777zut7JCYmypEjR/Qq6UpKSoqMGTNGjh07Vid0AfA+ghAAr1OhwO2DDz6Qxx9/XFJTU2v2tW7dWm9m4Imy+Pn56RW0AZgPTWMAvE6FAvcWERGha4hq71PB4/SmseTkZF0zc//990ubNm0kLi5OXn/9dSkuLpY777xTwsLCpFu3bvKf//ynzs/67rvv5PLLL9ffUz3n9ttvl5ycnCaX9fSmMXe5/vCHP+jvp2p0nnzySamsrJSHH35YoqKipEOHDvLmm2/W2zSm7qvaIEWdh9qvvicAYxCEAFjGW2+9pZuXNm/erEPRlClTZOLEiTJ8+HDZtm2bXHbZZTrolJSU6OPz8/PlZz/7mQwcOFC2bNkiy5cvl6NHj8oNN9xwXuVYtWqVHD58WNauXSt/+tOfdFPeVVddpYPNpk2b5N5775V77rlHDh48WG8z2T//+U99X9WCqdox1QwIwBgEIQCWMWDAAJk1a5Z0795dZs6cKcHBwToY3XXXXXqfamLLzc2VHTt26ONffPFFHYJU7U2vXr30/b/+9a+yevVq2b17d7PLoWp9nn/+eenZs6f893//t75V4evRRx+tKVtgYKB88cUX9TaTqecrbdu2rakVA2AM+ggBsIz+/fvXCRTR0dHSr1+/mn2qqUrJysrSt998840OPfX18cnIyJAePXo0qxx9+vQRX1/fOj+3b9++Z5TNXQ4A5kUQAmAZAQEBdb5W/Wtq73OPRquurta3RUVFcvXVV8u8efPO+F4JCQktVg73Pnc5AJgXQQiAbQ0aNEj3x+ncubP4+5vn7U41mylVVVVGFwVwPPoIAbCtqVOnSl5entx8883y1Vdf6eawTz/9VI8yMzKEdOrUSdcYLVu2TLKzs3XNFQBjEIQA2Fa7du1k/fr1OvSoEWWqP5Eafq+GvNfu4+Nt7du3lzlz5siMGTN0/6Jp06YZVhbA6XxcZpi6FQAAwADUCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAMciCAEAAHGq/wf6AekCIpkVggAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "x = runs_table[\"parameter\", \"timelimit\"]\n", "y = runs_table[\"solution_scip\", \"objective\"]\n", "plt.plot(x, y, \"o-\")\n", "plt.xlabel(\"Time limit\")\n", "plt.ylabel(\"Objective\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Save and Load Experimental Data\n", "\n", "By setting `auto_saving` to `False` in the `Experiment` constructor, you can disable automatic saving. In this case, you can save data at any time using the `Experiment.save` method. \n", "You can also load saved data using the `Experiment.load_from_dir` method." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# By default, data is saved under .minto_experiments/ directory\n", "experiment.save()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "exp2 = minto.Experiment.load_from_dir(\n", " \".minto_experiments/\" + experiment.experiment_name\n", ")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
solution_scipparametermetadata
objectivefeasibleoptimalityrelaxationstartnametimelimitrun_idelapsed_time
run_id
00.000000e+00True00Nonescip0.100.119688
1-3.027709e+07True00Nonescip0.510.399354
2-3.027709e+07True00Nonescip1.020.507941
3-3.027709e+07True00Nonescip2.031.009734
\n", "
" ], "text/plain": [ " solution_scip parameter \\\n", " objective feasible optimality relaxation start name timelimit \n", "run_id \n", "0 0.000000e+00 True 0 0 None scip 0.1 \n", "1 -3.027709e+07 True 0 0 None scip 0.5 \n", "2 -3.027709e+07 True 0 0 None scip 1.0 \n", "3 -3.027709e+07 True 0 0 None scip 2.0 \n", "\n", " metadata \n", " run_id elapsed_time \n", "run_id \n", "0 0 0.119688 \n", "1 1 0.399354 \n", "2 2 0.507941 \n", "3 3 1.009734 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exp2.get_run_table()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Saving and Load to/from OMMX Archive\n", "\n", "You can save and load data to/from OMMX Archive using the `Experiment.save_to_ommx_archive` and `Experiment.load_from_ommx_archive` methods." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "artifact = experiment.save_as_ommx_archive(\"scip_experiment.ommx\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
solution_scipparametermetadata
objectivefeasibleoptimalityrelaxationstartnametimelimitrun_idelapsed_time
run_id
00.000000e+00True00Nonescip0.100.119688
1-3.027709e+07True00Nonescip0.510.399354
2-3.027709e+07True00Nonescip1.020.507941
3-3.027709e+07True00Nonescip2.031.009734
\n", "
" ], "text/plain": [ " solution_scip parameter \\\n", " objective feasible optimality relaxation start name timelimit \n", "run_id \n", "0 0.000000e+00 True 0 0 None scip 0.1 \n", "1 -3.027709e+07 True 0 0 None scip 0.5 \n", "2 -3.027709e+07 True 0 0 None scip 1.0 \n", "3 -3.027709e+07 True 0 0 None scip 2.0 \n", "\n", " metadata \n", " run_id elapsed_time \n", "run_id \n", "0 0 0.119688 \n", "1 1 0.399354 \n", "2 2 0.507941 \n", "3 3 1.009734 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exp3 = minto.Experiment.load_from_ommx_archive(\"scip_experiment.ommx\")\n", "exp3.get_run_table()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Summary\n", "\n", "In this tutorial, we learned how to use `minto` for managing numerical experiments:\n", "\n", "1. **Installation** is straightforward via pip:\n", " ```bash\n", " pip install minto\n", " ```\n", "\n", "2. **Recording Experimental Data**\n", " - Used SCIP solver through OMMX interface\n", " - Conducted experiments with different time limits (0.1s to 2.0s)\n", " - Recorded instance data and solution results systematically\n", "\n", "3. **Data Management**\n", " - Automatic saving with `auto_saving=True`\n", " - Manual saving with `experiment.save()`\n", " - Data visualization using pandas DataFrame and matplotlib\n", " - Results showed objective values converging to -2.92e+07\n", "\n", "4. **Data Persistence**\n", " - Local storage in `.minto_experiments/` directory\n", " - OMMX archive format support.\n", " - Easy data recovery with `load_from_dir` and `load_from_ommx_archive`\n", "\n", "This workflow demonstrates `minto`'s capabilities for structured experimental management in optimization tasks." ] } ], "metadata": { "kernelspec": { "display_name": "minto-FuAFD3Cq-py3.10", "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.10.13" } }, "nbformat": 4, "nbformat_minor": 2 }