{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2232b758-63e1-41d2-9408-179a53a85aa2",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-807eca211e1487aa",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "# 4. Programmierübung: NumPy\n",
    "\n",
    "<div style=\"display:flex;\">\n",
    "    <div style=\"text-align: left\">\n",
    "        Willkommen zur vierten Programmierübung Einführung in Python 3.\n",
    "    </div>\n",
    "    <img style=\"float: right; margin: 0px 15px 15px 0px\" src=\"https://www.python.org/static/img/python-logo-large.c36dccadd999.png?1576869008\" width=\"100\" />\n",
    "</div>\n",
    "\n",
    "Wenn Sie Fragen oder Verbesserungsvorschläge zum Inhalt oder Struktur der Notebooks haben, dann können sie eine E-Mail an Phil Keier ([p.keier@hbk-bs.de](mailto:p.keier@hbk-bs.de?subject=[SigSys]%20Feedback%20Programmierübung&amp)) oder Martin Le ([martin.le@tu-bs.de](mailto:martin.le@tu-bs.de?subject=[SigSys]%20Feedback%20Programmierübung&amp)) schreiben.\n",
    "\n",
    "Link zu einem Python Spickzettel: [hier](https://s3.amazonaws.com/assets.datacamp.com/blog_assets/PythonForDataScience.pdf)\n",
    "\n",
    "Der Großteil des Python-Tutorials stammt aus der Veranstaltung _Deep Learning Lab_ und von [www.python-kurs.eu](https://www.python-kurs.eu/python3_kurs.php) und wurde für _Signale und Systeme_, sowie _Einführung in die Programmierung für Nicht Informatiker_ angepasst.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "789f42fa-8c0c-4c9e-8949-d3899f3e4049",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-1cd501e6cecd8b4f",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "# Was ist NumPy\n",
    "\n",
    "NumPy steht für *Numerical Python*, ist OpenSource und wird mittlerweile von nahezu jedem Python Entwickeler verwendet. Dabei ist das Core Feature von NumPy seine effiziente Implementierung eines n-dimensionales Arrays in C, welches in Python verwendet werden kann. Hinzu kommt eine Hülle an Funktionen wie effiziente Zufallsalgorithmen und mathematische Funktionen aus den unterschiedlichten Bereichen der Statistik und numerischen Berechnung, welche alle für NumPy Arrays Optimiert sind. Im folgenden wollen wir den Umgang mit NumPy Arrays lernen. \n",
    "\n",
    "__Für dieses Notebook schauen Sie bitte in die [NumPy Docs](https://numpy.org/doc/stable/reference/index.html)!!!__ Dort sind alle Funktionen beschrieben die wir hier bearbeiten und noch mehr!\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fc6f7d6-3d42-4890-8210-de78a1fb7458",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-4ae0a3d5075b3709",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Das gesamte Internet importiert NumPy mit dem Kürzel `np`. Um uns diesen ungeschriebenen Gesetz anzuschließen importieren wir in nächster Zelle NumPy als np:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "f0d7d531-4c9a-429a-bd65-ad07fa06fdfc",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-50e3611287e2c68f",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c75e273d-8fa1-4618-8107-4820753b548e",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-b910cff04746aa1d",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "# Was ist ein Array?\n",
    "\n",
    "Ein Array ist eine kontinuierliche Datenstrucktur. Dabei werden die Daten in Reihe im Arbeitsspeicher hinterlegt, vergleichbar mit der Python Liste.\n",
    "\n",
    "## Erstellen von Arrays\n",
    "\n",
    "Alle folgenden Beispiele finden Sie im [Beginners Guide](https://numpy.org/doc/stable/user/absolute_beginners.html).\n",
    "\n",
    "Für unser erstes Beispiel erstellen wir aus einer Python liste ein [NumPy Array](https://numpy.org/doc/stable/reference/arrays.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f7e32ba5-2ccc-47b0-82a7-a673cce4a5f1",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-1adaa95f01483572",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([1,2,3,4,5])\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9ea665d-900f-4e99-bddc-3ed990b0ac27",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-ea5067ebbb1c99bc",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Der Zugriff auf Elemente des Arrays erfolgt analog zu Pythons Liste:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "7e5103ab-0a56-4a5f-a594-410d50a59e2a",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-cb73ac88e9fa5d93",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[4]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccdab404-1ade-4622-a649-f1b7e594032a",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-ec0a814ecfda8547",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "NumPy Arrays sind n-dimensional, heißt Arrays in NumPy können aus geschachtelten Listen bestehen. Beispiel für ein 2-Dimensionales Array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "73b885f6-6fc8-4b45-ad60-d7a97ff3e0b1",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-ff72c8352626ac82",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3, 4, 5],\n",
       "       [6, 7, 8, 9, 8],\n",
       "       [7, 6, 5, 4, 3]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array(\n",
    "    [\n",
    "        [1,2,3,4,5],\n",
    "        [6,7,8,9,8],\n",
    "        [7,6,5,4,3],\n",
    "    ])\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2de1bfe6-f584-406a-b9b2-a84bd7119ae1",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-413fcd639649e39a",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Diese Datenstrucktur wird Allgemein auch Matrix gennant. Der Zugriff auf ein Element einer Matrix folgt nach dem Prinzip \"Spalte->Reihe\". Die erste Spalte ist demnach:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "f6a5cbff-1164-4a58-9821-d9dc1d22f413",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-c7a59ce293c8e402",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23357d46-1667-41fa-ae61-45d7919f946d",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-fb0cf79581b45e5e",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Der zugriff auf ein einzelnes element erfolgt dann analog:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "329c8ce4-e8e3-4a4f-bfb9-0f14fe14bd1f",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-2f107dba2b747fbb",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[0][4]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8575708-b436-4835-94ce-dcab2a630c59",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-617d777cf3216789",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Oder mit der NumPys eigener Syntax `arr[<spalte>, <reihe>]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "4dcd8136-5189-4bd1-a2f8-94380abe07a7",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-3e1e7323c57088ad",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[0, 4]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "235987ad-3ba9-4b2b-a516-7f4898f5a046",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-62701cdd045c7c4c",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Platzreservierung\n",
    "\n",
    "Falls bekannt ist wie viele Elemente ein Array im späteren Programmverlauf haben soll, bietet einem NumPy die möglichkeit diesen Platz im speicher gewissermaßen zu reservieren.\n",
    "Hierfür gibt es einige Funktionen.\n",
    "\n",
    "### Ones\n",
    "\n",
    "1 Dimensionales NumPy Array der größe 10 mit 1 gefüllt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a9473e4d-7632-4ad2-9dfc-9c1b45bbf4d1",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-d3aeedf2a30a9b30",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.ones(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d88eddf1-8102-4fa6-9e77-870283782f4a",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-6e683d4afe40b7ff",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "### Zeros\n",
    "\n",
    "Analog dazu mit 0 gefüllt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "87464631-34db-4e04-8772-e423dc73c3c6",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-450f40270416767a",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "682a6ac2-23d7-48d8-af09-5c5cb571645d",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-ef1e55c1165e2de5",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "### Empty\n",
    "\n",
    "Analog mit zufälligen Werten (bzw. Werte die bereits an der Speicherstelle waren, meistens 0):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "e7bae7f4-85f0-4d40-a108-114281052de1",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-896e48c096be9062",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.empty(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc587f64-5c44-41d8-b7f2-1c77e1833e45",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-947ed3289815694d",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "### Arange\n",
    "\n",
    "Analog dazu die `arange` Funktion (die Paramter sind die selben wie bei der Python `range` Funktion):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "87a59679-06ce-45a8-8a0c-1e38b5afa980",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-5329dd48e6129b33",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bde3e4d6-27dc-4a15-b09b-1a803f2ede97",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-299417e99c41e05f",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "### Linspace\n",
    "\n",
    "Um später mit Matplotlib besser arbeiten zu können hat Numpy die [linspace](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html#numpy-linspace) Funktion. Welche die Werte von einem Start und End Punkt Linear berechnet, zusätzlich kann noch die Anzahl der Elemete mit dem `num` Parameter angegeben werden:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "72a3c4e5-6a34-47c8-a6d9-0ee5f9344a7a",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-036bdec449f35dc5",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0. ,  2.5,  5. ,  7.5, 10. ])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(0,10, num=5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "461fce96-5a91-475e-976b-aa529419ed7d",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-9ac9d3f215fc0237",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 400.        ,  466.66666667,  533.33333333,  600.        ,\n",
       "        666.66666667,  733.33333333,  800.        ,  866.66666667,\n",
       "        933.33333333, 1000.        ])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(400, 1000, num=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2399ddc1-70df-4ee0-af8c-c5e0c7123d09",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-522faf35a6c76300",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Aufgabe\n",
    "\n",
    "Erstellen Sie ein NumPy Array, welches 6 Nullen reserviert und speichern Sie das Array in der Variablen `only_zeros`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "a94c515e-aacb-42b1-813c-5b9ac16c062f",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-176f6befb5f45c58",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    }
   },
   "outputs": [],
   "source": [
    "only_zeros = None\n",
    "# BEGIN SOLUTION\n",
    "only_zeros = np.zeros(6)\n",
    "# END SOLUTION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "66128e44-dbdb-40db-aa0d-ef73441ef7a1",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-8ad1e3a41d459d55",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0. 0. 0. 0. 0. 0.]\n"
     ]
    }
   ],
   "source": [
    "print(only_zeros)\n",
    "assert len(only_zeros) == 6\n",
    "### BEGIN HIDDEN TESTS\n",
    "for el in only_zeros:\n",
    "    assert el == 0\n",
    "### END HIDDEN TESTS"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91993511-9afc-4265-b88f-7507490fa77d",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-0108e88f3110e70f",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Aufgabe\n",
    "\n",
    "Erstellen Sie ein NumPy Array mit 11 Elementen mittels `linspace`, Dabei soll der Startwert = -4 und der Endwert = 17 sein. Speichern Sie das Ergbniss in der Variablen `x_scale`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "e8929ae8-a6e9-4fb5-bc9a-7d72493968cc",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-3231ee937ba8ab7a",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    }
   },
   "outputs": [],
   "source": [
    "x_scale = None\n",
    "# BEGIN SOLUTION\n",
    "x_scale = np.linspace(-4, 17, num=11)\n",
    "# END SOLUTION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "3b8ac0eb-d7f8-44ef-a238-c8292409a096",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-e5d66ef7599f7b91",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-4.  -1.9  0.2  2.3  4.4  6.5  8.6 10.7 12.8 14.9 17. ]\n"
     ]
    }
   ],
   "source": [
    "# Hier werden ihre Lösungen getestet\n",
    "print(x_scale)\n",
    "assert len(x_scale) == 11\n",
    "### BEGIN HIDDEN TESTS\n",
    "s = np.linspace(-4, 17, num=11)\n",
    "for el1, el2 in zip(x_scale, s):\n",
    "    assert el1 == el2\n",
    "### END HIDDEN TESTS"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b581b99-4938-491e-bc56-b4090a8134e4",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-a33f2b356b5c882d",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Sortieren\n",
    "\n",
    "Es gibt viele Sortieralgorithmen in der freien Wildbahn des Internets NumPy hat dies für uns bereits implementiert.\n",
    "Wollen wir im folgenden eine Liste sortieren nutzen wir die `sort` Funktion:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "33d435f4-1326-4077-b39e-7da2886b4d90",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-598991a2c733ce85",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Unsortiertes Array: [         14        9292       -1267         929           7           7\n",
      "          42 -4294967297]\n",
      "Sortiertes Array: [-4294967297       -1267           7           7          14          42\n",
      "         929        9292]\n"
     ]
    }
   ],
   "source": [
    "unsorted = np.array([14, 9292, -1267, 929, 7, 7, 42, -2**32-1])\n",
    "print(\"Unsortiertes Array:\", unsorted)\n",
    "sorted = np.sort(unsorted)\n",
    "print(\"Sortiertes Array:\", sorted)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9dcc9f48-aa79-43cf-a84e-5b0ab4d5fc05",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-8b154c89f933387e",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Aufgabe\n",
    "\n",
    "Ihnen ist das Array `pcgs` gegeben dieses enthält zufällige Zahlen eines _Permuted Congruent Generators_. Nutzen Sie Numpy um die Werte des Arrays `pcgs` zu sortieren. Speichern Sie ihr Ergebnis in der Variablen `sorted_pcgs`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "f011df4d-29ff-4064-b41f-6f008cc75674",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-2191ff9a88bb6ca0",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[91.67441575549084,\n",
       " 46.74907799518424,\n",
       " 7.123920291270869,\n",
       " 76.39328676507445,\n",
       " 1.7567502091441867,\n",
       " 25.302055214458075,\n",
       " 63.618561250625696,\n",
       " 0.1579146041553514,\n",
       " 70.96566546463475,\n",
       " 29.830322658786066,\n",
       " 32.993271323881935,\n",
       " 85.498191941231,\n",
       " 28.897614421550255,\n",
       " 7.23902480784705,\n",
       " 70.31144257136475,\n",
       " 24.870797377171648,\n",
       " 15.503033920124121,\n",
       " 20.10861125030664,\n",
       " 46.93021735717943,\n",
       " 47.12091752159737]"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Führen Sie diese Zelle aus bevor Sie die Aufgabe lösen\n",
    "from numpy.random import SeedSequence, Generator, PCG64\n",
    "sg = SeedSequence(42)\n",
    "pcgs = [Generator(PCG64(s)).random()*100 for s in sg.spawn(20)]\n",
    "pcgs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "ddc61400-dffb-4bce-8ebc-e610c532b68f",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-4b0e6942a521f2a6",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    }
   },
   "outputs": [],
   "source": [
    "sorted_pcgs = None\n",
    "# BEGIN SOLUTION\n",
    "sorted_pcgs = np.sort(pcgs)\n",
    "# END SOLUTION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "08580054-e47d-43b0-a5d8-5b7addf27bc8",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-117b9c5d3b8c4bc3",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 49996 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Visualisierung ihrer Lösung\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "plt.plot(np.arange(len(sorted_pcgs)), pcgs, color='r', label='PCGs')\n",
    "plt.plot(np.arange(len(sorted_pcgs)), sorted_pcgs, color='g', label='Sortierte PCGs')\n",
    "plt.title(\"PCG Random Numbers\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "84eccf42-7069-423d-a908-d2461f8347f5",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-869d69a5298f07f5",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.1579146   1.75675021  7.12392029  7.23902481 15.50303392 20.10861125\n",
      " 24.87079738 25.30205521 28.89761442 29.83032266 32.99327132 46.749078\n",
      " 46.93021736 47.12091752 63.61856125 70.31144257 70.96566546 76.39328677\n",
      " 85.49819194 91.67441576]\n"
     ]
    }
   ],
   "source": [
    "# Hier werden ihre Lösungen getestet\n",
    "print(sorted_pcgs)\n",
    "### BEGIN HIDDEN SOLUTION\n",
    "for s, t in zip(sorted_pcgs, np.sort(pcgs)):\n",
    "    assert s == t\n",
    "### END HIDDEN SOLUTION"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48b5d761-b906-4cef-b267-05e0fba53eeb",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-3d85ded8d3cf26fe",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Operationen auf Arrays\n",
    "\n",
    "NumPy hat die Operationen `+`, `-`, `*`, `/` und `%` alle von Haus aus Implementiert. Bei der Berechnung werden die Werte Suksessziv nacheinander miteinander Verküpft. Also `n1[0] + n2[0]`, `n1[1] + n2[1]`, ..., `n1[-1] + n2[-1]`,\n",
    "\n",
    "Schauen wir uns dazu die beiden Arrays `n1` & `n2` an."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "id": "32ad77b3-5411-42bb-a0c9-c2d098e2e945",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-a69046941c198fba",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N1: [1 2 3 4]\n",
      "N2: [11 12 13 14]\n",
      "\n",
      "N1 + N2: [12 14 16 18]\n",
      "N2 - N1: [10 10 10 10]\n",
      "N1 * N2: [11 24 39 56]\n",
      "N1 / N2: [0.09090909 0.16666667 0.23076923 0.28571429]\n",
      "N1 % N2: [1 2 3 4]\n"
     ]
    }
   ],
   "source": [
    "n1 = np.arange(1, 5)\n",
    "n2 = np.arange(11, 15)\n",
    "\n",
    "print(\"N1:\", n1)\n",
    "print(\"N2:\", n2)\n",
    "print()\n",
    "print(\"N1 + N2:\", n1 + n2)\n",
    "print(\"N2 - N1:\", n2 - n1)\n",
    "print(\"N1 * N2:\", n1 * n2)\n",
    "print(\"N1 / N2:\", n1 / n2)\n",
    "print(\"N1 % N2:\", n1 % n2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f067243-b0a2-4e42-8373-7a9e6a3ebfe3",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-96fcc4ed333e3844",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Das ganze Funktioniert nur und ausschließlich dann wenn beide Arrays dieselbe größe haben. Folglich läuft die Addition von Array `n1` mit Array `n3` auf einen Fehler, da Array `n3` 2 Elemente mehr Enthält:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "id": "0495d52f-905a-4720-ac98-78963848022c",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-e0da1d4c3a72f279",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N3: [21 22 23 24 25 26]\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "operands could not be broadcast together with shapes (4,) (6,) ",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[96], line 3\u001b[0m\n\u001b[1;32m      1\u001b[0m n3 \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m21\u001b[39m, \u001b[38;5;241m27\u001b[39m)\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mN3:\u001b[39m\u001b[38;5;124m\"\u001b[39m, n3)\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFehler N1 + N3:\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[43mn1\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mn3\u001b[49m)\n",
      "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (4,) (6,) "
     ]
    }
   ],
   "source": [
    "n3 = np.arange(21, 27)\n",
    "print(\"N3:\", n3)\n",
    "print(\"Fehler N1 + N3:\", n1 + n3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71155576-c6f8-4954-86ef-216190093749",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-8b7f52332c7aa8c6",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Shapes\n",
    "\n",
    "Um diesen Fehler vorzubeugen hat jedes NumPy Array den Parameter `shape`. Für `n1` ist dieser 4 und `n3` ist dieser 6."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "5311416a-992d-4c93-8522-440094135009",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-102dbd7036166206",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape von N1: (4,)\n",
      "Shape von N3: (6,)\n"
     ]
    }
   ],
   "source": [
    "print(\"Shape von N1:\", n1.shape)\n",
    "print(\"Shape von N3:\", n3.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a1914ad-d9bf-47f6-85bf-b9f62e33be37",
   "metadata": {},
   "source": [
    "Vielleicht wundern Sie sich warum die Ausgabe `(4,)` bringt. Das liegt daran das Shape multidimensional ist. Schauen wir uns die Matrix `m` bestehend aus `n1` & `n2` an:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "id": "b3a16e98-3b1e-4bf3-87fa-918bd84b8956",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-bcec8661f2166849",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "M: [[ 1  2  3  4]\n",
      " [11 12 13 14]]\n",
      "Shape M: (2, 4)\n"
     ]
    }
   ],
   "source": [
    "m = np.array([n1, n2])\n",
    "print(\"M:\", m)\n",
    "print(\"Shape M:\", m.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7b66742-f5f6-47a7-bd07-eb489b8bbf39",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-b3f898e60d8e3617",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Es ist dementsprechend wichtig den Shape zu prüfen wenn Sie sich nicht Sicher sind ob zwei Arrays miteinander verknüpft werden können:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "dc836d79-b6ac-4386-9dbc-d26c3ce80551",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-048c10a814175dd3",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Error\n"
     ]
    }
   ],
   "source": [
    "if n1.shape == n3.shape:\n",
    "    print(\"N1 + N3:\", n1 + n3)\n",
    "else:\n",
    "    print(\"Error\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b63c961-51da-4eb2-b749-caf1af15ff92",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-d3583eabd1371892",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Aufgabe\n",
    "\n",
    "Schauen Sie in die NumPy Dokumentation zur Funktion [reshape](https://numpy.org/doc/stable/reference/generated/numpy.reshape.html#numpy.reshape). Und shapen Sie das Array `n3` in eine Matrix der Form 3x2. Speicher Sie ihr Ergebnis in der Variablen `m23`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "051ed23d-ca7e-417f-843f-39b3276d522d",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-c41f34a6ae05874e",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    }
   },
   "outputs": [],
   "source": [
    "m23 = None\n",
    "# BEGIN SOLUTION\n",
    "m23 = n3.reshape((3, 2))\n",
    "# END SOLUTION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "9fbbfd0b-49d9-47ea-9980-5df125ddb62a",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-973d2b07d04862ab",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[21 22]\n",
      " [23 24]\n",
      " [25 26]]\n"
     ]
    }
   ],
   "source": [
    "# Hier werden ihre Lösungen getestet\n",
    "print(m23)\n",
    "assert m23.shape == (3,2)\n",
    "### BEGIN HIDDEN TESTS\n",
    "l = n3.reshape((3, 2))\n",
    "for s, t in zip(m23, l):\n",
    "    for el1, el2 in zip(s, t):\n",
    "        assert el1 == el2\n",
    "### END HIDDEN TESTS"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
