{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5452 characters]",
      "text/plain": [
       "<Figure size 432x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Aufgabe 1\n",
    "import numpy as np\n",
    "\n",
    "rng = np.random.default_rng()\n",
    "\n",
    "values = [rng.standard_normal(10), rng.standard_normal(100), rng.standard_normal(1000)]\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "fig, axs = plt.subplots(3)\n",
    "\n",
    "for i in range(3):\n",
    "    axs[i].hist(values[i])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Aufgabe 2\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "rng = np.random.default_rng()\n",
    "\n",
    "n = 5\n",
    "values = rng.integers(low=0, high=2, size=n)\n",
    "\n",
    "while sum(values) < n:\n",
    "    values = [v ^ 1 if rng.random() > 0.1 else v for v in values]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5412 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Aufgabe 3\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "rng = np.random.default_rng()\n",
    "\n",
    "\n",
    "def bitflip(n: int = 5) -> int:\n",
    "    values = rng.integers(low=0, high=2, size=n)\n",
    "\n",
    "    counter = 0\n",
    "    while sum(values) < n:\n",
    "        counter += 1\n",
    "        values = [v ^ 1 if rng.random() > 0.1 else v for v in values]\n",
    "\n",
    "    return counter\n",
    "\n",
    "\n",
    "counts = [bitflip() for _ in range(100)]\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.hist(counts)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 64404 characters]",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Aufgabe 4\n",
    "\n",
    "\n",
    "def rosenbrock(x, y):\n",
    "    return ((1 - x) ** 2) + 100 * ((y - (x**2)) ** 2)\n",
    "\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "x = np.linspace(start=-2.0, stop=2.0, num=1000)\n",
    "y = np.linspace(start=-1.0, stop=3.0, num=1000)\n",
    "X, Y = np.meshgrid(x, y)\n",
    "Z = rosenbrock(X, Y)\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.colors import LogNorm\n",
    "\n",
    "\n",
    "# 4.1\n",
    "fig, ax = plt.subplots(1,1, facecolor=\"w\")\n",
    "im = ax.imshow(Z, norm=LogNorm(), origin=\"lower\", extent=[-2, 2, -1, 3])\n",
    "cset = ax.contour(X, Y, Z, [0.1, 1, 10, 100, 1000], colors=\"#ffffff\", linewidths=1)\n",
    "fig.colorbar(im)  # adding the colorbar on the right\n",
    "ax.plot(1, 1, color=\"black\", marker=\"+\", markersize=20) # minimum\n",
    "\n",
    "\n",
    "# 4.2\n",
    "rng = np.random.default_rng()\n",
    "\n",
    "popsize = 30\n",
    "population = zip(rng.uniform(-2, 2, size=popsize), rng.uniform(-1, 3, size=popsize))\n",
    "population = sorted(population, key=lambda p: rosenbrock(p[0], p[1]))\n",
    "top3 = list(zip(*population[:3]))\n",
    "points = ax.scatter(*top3, color=\"#353535\")\n",
    "\n",
    "# 4.3\n",
    "import time\n",
    "from IPython import display\n",
    "hdisplay = display.display(\"\", display_id=True)\n",
    "\n",
    "selsize = 10\n",
    "generations = 30\n",
    "\n",
    "for g in range(generations):\n",
    "    # Sort population by fitness\n",
    "    population = sorted(population, key=lambda p: rosenbrock(p[0], p[1]))\n",
    "    selection = list(zip(*population[:selsize]))\n",
    "\n",
    "    # Plot population\n",
    "    points.remove()\n",
    "    points = ax.scatter(*selection, color=\"#353535\")\n",
    "    ax.title.set_text(f\"Generation: {g}\")\n",
    "    hdisplay.update(fig)\n",
    "\n",
    "    # Wait\n",
    "    time.sleep(0.5)\n",
    "\n",
    "    # Recombination\n",
    "    population = []\n",
    "    for _ in range(popsize - selsize):\n",
    "        parents = (rng.choice(selection), rng.choice(selection))\n",
    "        population.append(((parents[0][0] + parents[1][0]) / 2, (parents[0][1] + parents[1][1]) / 2))\n",
    "    population += selection\n",
    "\n",
    "    # Mutation\n",
    "    m = 0.5 * np.exp(-0.1 * g)\n",
    "    population = [(p[0] + rng.normal(scale=m), p[1] + rng.normal(scale=m)) for p in population]\n",
    "\n",
    "plt.close()\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.10.4"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
