{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Solving Sudokus Like a Master\n\nThis example demostrates how to use the low-sugar in combination with mlflow\nto solve sudoku puzzles.\n\n<img src=\"https://mybinder.org/badge_logo.svg\" target=\"https://mybinder.org/v2/gh/juandados/opt-sugar/main?labpath=doc%2Fsource%2Fauto_examples%2Fplot_sudoku.ipynb\">\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# sphinx_gallery_thumbnail_path = '_static/sudoku.png'\nfrom itertools import product\nimport datetime\nimport numpy as np\n\nimport mlflow\nfrom mlflow import MlflowException\nimport pandas as pd\n\nimport gurobipy as gp\n\n# import sys; sys.path.append(\"/Users/Juan.ChaconLeon/opt/opt-sugar/src\")  # when running locally\nfrom opt_sugar import low_sugar\nfrom opt_sugar import opt_flow\nfrom utils.sudoku import show_sudoku\n\n\nexperiment_name = f\"sudoku_{datetime.datetime.now().strftime('%Y_%m_%d')}\"\ntry:\n    experiment_id = mlflow.create_experiment(name=experiment_name)\nexcept MlflowException:\n    experiment_id = mlflow.get_experiment_by_name(name=experiment_name).experiment_id\n\nwith mlflow.start_run(experiment_id=experiment_id):\n\n    def build(data):\n        # Create a new model\n        m = gp.Model(\"sudoku\")\n\n        # Create Indices\n        pos_ys = list(range(3))\n        pos_xs = list(range(3))\n        square_ys = list(range(3))\n        square_xs = list(range(3))\n        positions = list(product(pos_ys, pos_xs, square_ys, square_xs))\n\n        digits = list(range(1, 10))\n        indices = list((*pos, digit) for pos, digit in product(positions, digits))\n\n        # Create variables\n        digit_pick = m.addVars(indices, vtype=\"B\", name=\"digit_pick\")\n\n        # Set objective: This is a feasibility problem rather than on optimization one.\n        m.setObjective(0)\n\n        # Add constraints:\n        for pos_y, square_y, digit in product(pos_ys, square_ys, digits):\n            m.addConstr(\n                digit_pick.sum(pos_y, \"*\", square_y, \"*\", digit) == 1,\n                name=f\"row_{pos_y}_{square_y}_{digit}\",\n            )\n\n        for pos_x, square_x, digit in product(pos_xs, square_xs, digits):\n            m.addConstr(\n                digit_pick.sum(\"*\", pos_x, \"*\", square_x, digit) == 1,\n                name=f\"col_{pos_x}_{square_x}_{digit}\",\n            )\n\n        for square_y, square_x, digit in product(square_ys, square_xs, digits):\n            m.addConstr(\n                digit_pick.sum(\"*\", \"*\", square_y, square_x, digit) == 1,\n                name=f\"square_{square_y}_{square_x}_{digit}\",\n            )\n\n        for pos_y, pos_x, square_y, square_x in positions:\n            y = square_y * 3 + pos_y\n            x = square_x * 3 + pos_x\n            chosen_digit = data[y][x]\n            if chosen_digit:\n                chosen_digit = int(chosen_digit)\n                m.addConstr(\n                    digit_pick[pos_y, pos_x, square_y, square_x, chosen_digit] == 1,\n                    name=f\"chosen_{pos_y}_{pos_x}_{square_y}_{square_x}_{chosen_digit}\",\n                )\n\n        for pos_y, pos_x, square_y, square_x in positions:\n            m.addConstr(\n                digit_pick.sum(pos_y, pos_x, square_y, square_x, \"*\") == 1,\n                name=f\"position_{pos_y}_{pos_x}_{square_y}_{square_x}_chosen\",\n            )\n\n        return m\n\n    examples_path = (\n        \"https://raw.githubusercontent.com/juandados/opt-sugar/main/examples/data\"\n    )\n    data = (\n        pd.read_csv(f\"{examples_path}/sudoku_1.csv\", header=None)\n        .replace({np.NaN: None})\n        .values\n    )\n\n    # Building\n    opt_model = low_sugar.Model(build)\n    result = opt_model.optimize(data=data)\n    show_sudoku(vars=result[\"vars\"][\"digit_pick\"])\n    model_info = mlflow.sklearn.log_model(opt_model, \"opt_model\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Load the Registered Model and Optimize with new Data\n\nAdd description here.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "logged_model_uri = model_info.model_uri\nprint(f\"logged_model_uri: {logged_model_uri}\")\n\n# Load model as a PyFuncModel.\nloaded_model = opt_flow.pyfunc.load_model(logged_model_uri)\n\nexamples_path = (\n    \"https://raw.githubusercontent.com/juandados/opt-sugar/main/examples/data\"\n)\ndata = (\n    pd.read_csv(f\"{examples_path}/sudoku_2.csv\", header=None)\n    .replace({np.NaN: None})\n    .values\n)\nresult = loaded_model.optimize(data=data)\n\n# Using a util function (Check imports)\nshow_sudoku(vars=result[\"vars\"][\"digit_pick\"])\nprint(f\"solution from the registered model {result['objective_value']}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<img src=\"https://mybinder.org/badge_logo.svg\" target=\"https://mybinder.org/v2/gh/juandados/opt-sugar/main?labpath=doc%2Fsource%2Fauto_examples%2Fplot_sudoku.ipynb\">\n\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "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.15"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}