{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simple example of TuRBO-m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from turbo import TurboM\n",
    "import numpy as np\n",
    "import torch\n",
    "import math\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set up an optimization problem class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Levy:\n",
    "    def __init__(self, dim=10):\n",
    "        self.dim = dim\n",
    "        self.lb = -5 * np.ones(dim)\n",
    "        self.ub = 10 * np.ones(dim)\n",
    "        \n",
    "    def __call__(self, x):\n",
    "        assert len(x) == self.dim\n",
    "        assert x.ndim == 1\n",
    "        assert np.all(x <= self.ub) and np.all(x >= self.lb)\n",
    "        w = 1 + (x - 1.0) / 4.0\n",
    "        val = np.sin(np.pi * w[0]) ** 2 + \\\n",
    "            np.sum((w[1:self.dim - 1] - 1) ** 2 * (1 + 10 * np.sin(np.pi * w[1:self.dim - 1] + 1) ** 2)) + \\\n",
    "            (w[self.dim - 1] - 1) ** 2 * (1 + np.sin(2 * np.pi * w[self.dim - 1])**2)\n",
    "        return val\n",
    "\n",
    "f = Levy(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create a Turbo optimizer instance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using dtype = torch.float64 \n",
      "Using device = cpu\n"
     ]
    }
   ],
   "source": [
    "turbo_m = TurboM(\n",
    "    f=f,  # Handle to objective function\n",
    "    lb=f.lb,  # Numpy array specifying lower bounds\n",
    "    ub=f.ub,  # Numpy array specifying upper bounds\n",
    "    n_init=10,  # Number of initial bounds from an Symmetric Latin hypercube design\n",
    "    max_evals=1000,  # Maximum number of evaluations\n",
    "    n_trust_regions=5,  # Number of trust regions\n",
    "    batch_size=10,  # How large batch size TuRBO uses\n",
    "    verbose=True,  # Print information from each batch\n",
    "    use_ard=True,  # Set to true if you want to use ARD for the GP kernel\n",
    "    max_cholesky_size=2000,  # When we switch from Cholesky to Lanczos\n",
    "    n_training_steps=50,  # Number of steps of ADAM to learn the hypers\n",
    "    min_cuda=1024,  # Run on the CPU for small datasets\n",
    "    device=\"cpu\",  # \"cpu\" or \"cuda\"\n",
    "    dtype=\"float64\",  # float64 or float32\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run the optimization process"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TR-0 starting from: 24.79\n",
      "TR-1 starting from: 20.77\n",
      "TR-2 starting from: 14.87\n",
      "TR-3 starting from: 27.97\n",
      "TR-4 starting from: 23.89\n",
      "80) New best @ TR-2: 12.43\n",
      "90) New best @ TR-2: 6.42\n",
      "110) New best @ TR-2: 5.467\n",
      "180) New best @ TR-2: 2.888\n",
      "230) New best @ TR-1: 1.944\n",
      "280) New best @ TR-1: 1.54\n",
      "310) New best @ TR-1: 1.052\n",
      "340) New best @ TR-1: 1.038\n",
      "390) New best @ TR-1: 0.9689\n",
      "410) New best @ TR-1: 0.877\n",
      "420) New best @ TR-1: 0.7794\n",
      "460) New best @ TR-1: 0.7509\n",
      "470) New best @ TR-1: 0.7264\n",
      "480) New best @ TR-1: 0.7238\n",
      "530) New best @ TR-1: 0.7044\n",
      "540) New best @ TR-1: 0.695\n",
      "550) New best @ TR-1: 0.6823\n",
      "560) New best @ TR-1: 0.6656\n",
      "590) New best @ TR-1: 0.6614\n",
      "600) New best @ TR-1: 0.6604\n",
      "640) TR-1 converged to: : 0.6604\n",
      "640) TR-1 is restarting from: : 23.66\n"
     ]
    }
   ],
   "source": [
    "turbo_m.optimize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Extract all evaluations from Turbo and print the best"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best value found:\n",
      "\tf(x) = 0.660\n",
      "Observed at:\n",
      "\tx = [-2.968  1.072  0.173  0.973  3.698  0.883  0.946  0.872  0.006  0.927]\n"
     ]
    }
   ],
   "source": [
    "X = turbo_m.X  # Evaluated points\n",
    "fX = turbo_m.fX  # Observed values\n",
    "ind_best = np.argmin(fX)\n",
    "f_best, x_best = fX[ind_best], X[ind_best, :]\n",
    "\n",
    "print(\"Best value found:\\n\\tf(x) = %.3f\\nObserved at:\\n\\tx = %s\" % (f_best, np.around(x_best, 3)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plot the progress\n",
    "\n",
    "TuRBO-5 converges to a solution close to the global optimum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 38536 characters]\n",
      "text/plain": [
       "<Figure size 504x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(7, 5))\n",
    "matplotlib.rcParams.update({'font.size': 16})\n",
    "plt.plot(fX, 'b.', ms=10)  # Plot all evaluated points as blue dots\n",
    "plt.plot(np.minimum.accumulate(fX), 'r', lw=3)  # Plot cumulative minimum as a red line\n",
    "plt.xlim([0, len(fX)])\n",
    "plt.ylim([0, 30])\n",
    "plt.title(\"10D Levy function\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
