{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "73703282",
   "metadata": {},
   "source": [
    "## Lecture 18, 16 October 2025"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44b502e8",
   "metadata": {
    "id": "9XZ7Vgb5PgAJ"
   },
   "source": [
    "# Using numpy\n",
    "\n",
    "- Arrays and lists\n",
    "- Arrays are \"homogenous\" with regular structure\n",
    "- Lists are flexible"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee8a759c",
   "metadata": {
    "id": "7J8WHOI8PgAK"
   },
   "source": [
    "### Load numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9dc84890",
   "metadata": {
    "id": "h320Z7OIPgAL"
   },
   "outputs": [],
   "source": [
    "import numpy as np  # Shortcut, use np for numpy in code"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e7b5431",
   "metadata": {},
   "source": [
    "### Constructing arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d5f6633",
   "metadata": {},
   "source": [
    "`np.array()` constructs an array from an input sequence\n",
    "- Sequence can be a list, tuple, output of a `range()` command ...\n",
    "- Size of the array is fixed by the sequence\n",
    "- Underlying type is also fixed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bcf998e6",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Toz_61yQ0cFA",
    "outputId": "dc2017b3-06ea-4043-87d8-f16bb7dd80a0"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.array(range(10))\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b75fe395-91b4-4422-8536-b9851de9ecee",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('int64')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.dtype # Underlying datatype of b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e97ded7",
   "metadata": {},
   "source": [
    "Use nested sequences to produce multi-dimensional arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9677ff9",
   "metadata": {},
   "source": [
    "- A 2d array is an array of 1d arrays\n",
    "- Note: can mix and match notation for sequences, but dimensions much match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "321bae2f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 0],\n",
       "       [2, 3, 2]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.array([(0,1,0),[2,3,2]])\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e8a63051-a542-4dcf-9c6d-5022b403ebe2",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m c = \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43marray\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m(\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m      2\u001b[39m c\n",
      "\u001b[31mValueError\u001b[39m: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part."
     ]
    }
   ],
   "source": [
    "c = np.array([(0,1,0),[2,2]])\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "42771b6c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 0],\n",
       "       [0, 1, 2]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = np.array([(0,1,0),range(3)])\n",
    "d  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67520cf0",
   "metadata": {},
   "source": [
    "- A 3d array is an array of 2d arrays"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "4b678167",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "yHc44L_a0pp4",
    "outputId": "60dbf89b-1b67-47f6-ad4d-eae28c884866"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[0, 1, 0],\n",
       "        [2, 3, 2]],\n",
       "\n",
       "       [[4, 5, 4],\n",
       "        [6, 7, 6]]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = np.array([[(0,1,0),[2,3,2]],[[4,5,4],[6,7,6]]])\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "5fd3677e-b375-43fd-8baf-e543c8bc7ec6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0.],\n",
       "       [0., 0., 0.],\n",
       "       [0., 0., 0.],\n",
       "       [0., 0., 0.],\n",
       "       [0., 0., 0.]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_zeros = np.zeros((5,3))  # np.zeros(shape), shape = (dim1,dim2,...,dimk)\n",
    "m_zeros"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "724d05b7-0fb8-4c4c-a520-60d0a0ffb1de",
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "Cannot interpret '3' as a data type",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mTypeError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m m_zeros = \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mzeros\u001b[49m\u001b[43m(\u001b[49m\u001b[32;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[32;43m3\u001b[39;49m\u001b[43m)\u001b[49m\n",
      "\u001b[31mTypeError\u001b[39m: Cannot interpret '3' as a data type"
     ]
    }
   ],
   "source": [
    "m_zeros = np.zeros(5,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "1ec3a2b3-cc91-4180-97cd-b172d8b192f0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_zeros.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "96052377-3cc8-4a49-8437-5d4d100db706",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 0, 0, 0, 0])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_zero_int = np.zeros(7,dtype='int64')\n",
    "m_zero_int"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "edf7a706-95ff-49cf-a322-92566fcb59cc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]],\n",
       "\n",
       "       [[1., 1., 1.],\n",
       "        [1., 1., 1.]]])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_ones = np.ones((8,2,3))\n",
    "m_ones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "97f6f810-601a-48ea-bc90-29f6b1f76b82",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.61478095, 0.66873022, 0.95844102, 0.42150011, 0.4276577 ,\n",
       "        0.4466395 ],\n",
       "       [0.4091643 , 0.19277623, 0.64426873, 0.29413532, 0.3060221 ,\n",
       "        0.55254819],\n",
       "       [0.96782399, 0.64445448, 0.30810994, 0.22376551, 0.87498372,\n",
       "        0.34494317],\n",
       "       [0.69119246, 0.57612184, 0.57630797, 0.92630779, 0.64981307,\n",
       "        0.38438788]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_rand = np.random.random((4,6))\n",
    "m_rand"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ac594150-3a0d-4086-b0cc-04925a7e3400",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[89, 84, 64, 20],\n",
       "       [10, 51, 13, 23],\n",
       "       [ 2, 35,  5, 34]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_rand_int = np.random.randint(1,100,(3,4))\n",
    "m_rand_int"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "d56108bc-c197-4ee8-905b-a79fa27c89f0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 2.25324418,  0.02261622],\n",
       "       [ 0.46259818, -0.28531591],\n",
       "       [-0.83403691, -2.6713428 ],\n",
       "       [ 1.17590504, -1.09052901],\n",
       "       [-0.98658065, -0.21246764]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_normal = np.random.normal(0,1,(5,2))   # np.normal(mean, std_dev, shape)\n",
    "m_normal"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76e1a8f3",
   "metadata": {},
   "source": [
    "### Broadcasting\n",
    "- In simplest form, scalar operations applied pointwise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "07f73f8e",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "0tbpjYMIPgAN",
    "outputId": "183f21e4-4d1a-42d3-9562-93e2350dc672"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.arange(10)  # arange(n) is same as array(range(n))\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "d0b6942d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a**3  # Replace each element by its cube  --- [ x**3 for x in a ]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "b17c7c55",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a+3   # Add 3 to each element"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d6ac7180",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  3,  6,  9, 12, 15, 18, 21, 24, 27])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3*a   # Multiply each element by 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "2d13102d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3+a   # Same as a+3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "84bd35fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([-3, -2, -1,  0,  1,  2,  3,  4,  5,  6]),\n",
       " array([ 3,  2,  1,  0, -1, -2, -3, -4, -5, -6]))"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a-3, 3-a  # Order is important because subtraction is not commutative"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "6633740a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([    1,     3,     9,    27,    81,   243,   729,  2187,  6561,\n",
       "       19683])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3**a  # Powers of 3"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8084dbf3",
   "metadata": {
    "id": "GWB0pizJPgAV"
   },
   "source": [
    "### Stacking arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24b111b5",
   "metadata": {},
   "source": [
    "- `np.random.random(m,n)` creates an $m x n$ array with random numbers drawn uniformly from $[0,1)$\n",
    "- `10*np.random.random()` scales the entries by 10\n",
    "- `np.floor()` removes the fractional part"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "67bf845b",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "S5O3dYahPgAV",
    "outputId": "d37a6b01-d3a6-4611-a5ed-661f7d2df7c5"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[4. 1.]\n",
      " [6. 9.]]\n",
      "[[1. 5.]\n",
      " [2. 1.]\n",
      " [5. 2.]]\n"
     ]
    }
   ],
   "source": [
    "a = np.floor(10*np.random.random((2,2)))\n",
    "b = np.floor(10*np.random.random((3,2)))\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "241006b5",
   "metadata": {},
   "source": [
    "- `vstack()` stacks a sequence of arrays vertically -- should have same number of columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "fe93dae6",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "plK9_37KPgAV",
    "outputId": "1b437dc4-4d7e-492e-a342-47ea684db598"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4., 1.],\n",
       "       [6., 9.],\n",
       "       [1., 5.],\n",
       "       [2., 1.],\n",
       "       [5., 2.]])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack((a,b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7031f063",
   "metadata": {},
   "source": [
    "- Cannot `vstack()` if number of columns don't match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "8f72029d",
   "metadata": {
    "id": "Yk1_M6ygPgAW"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[2., 8., 2.],\n",
       "       [9., 4., 9.]])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.floor(10*np.random.random((2,3)))\n",
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "ccbe8370",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 374
    },
    "id": "kFT-DWFKPgAW",
    "outputId": "7590a8b7-9ff0-42cf-b68b-1c54cbb22e5c"
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "all the input array dimensions except for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 3",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[27]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mvstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[43mc\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m~/python-venv/lib/python3.13/site-packages/numpy/_core/shape_base.py:292\u001b[39m, in \u001b[36mvstack\u001b[39m\u001b[34m(tup, dtype, casting)\u001b[39m\n\u001b[32m    290\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(arrs, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[32m    291\u001b[39m     arrs = (arrs,)\n\u001b[32m--> \u001b[39m\u001b[32m292\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_nx\u001b[49m\u001b[43m.\u001b[49m\u001b[43mconcatenate\u001b[49m\u001b[43m(\u001b[49m\u001b[43marrs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcasting\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcasting\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[31mValueError\u001b[39m: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 3"
     ]
    }
   ],
   "source": [
    "np.vstack((a,c))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d041f06d",
   "metadata": {},
   "source": [
    "- Number of rows does not matter if columns match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "d3a3340f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 2.],\n",
       "       [2., 2.],\n",
       "       [6., 0.]])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = np.floor(10*np.random.random((3,2)))\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "c8199ea5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4., 1.],\n",
       "       [6., 9.],\n",
       "       [1., 2.],\n",
       "       [2., 2.],\n",
       "       [6., 0.]])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack((a,d))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4c89c20",
   "metadata": {},
   "source": [
    "- Can stack any length sequence of arrays, not just two arrays"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "af178539",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4., 1.],\n",
       "       [6., 9.],\n",
       "       [1., 5.],\n",
       "       [2., 1.],\n",
       "       [5., 2.],\n",
       "       [1., 2.],\n",
       "       [2., 2.],\n",
       "       [6., 0.]])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack([a,b,d])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e43043af",
   "metadata": {},
   "source": [
    "- Likewise, `hstack()` stacks horizontally, number of rows must match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "2d5ea8bc",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "0wlDpZXFPgAW",
    "outputId": "4cc239ae-06a6-4e8a-ff0f-9f3b156f5ec8"
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "all the input array dimensions except for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 1 has size 3",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[31]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mhstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[43mb\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m~/python-venv/lib/python3.13/site-packages/numpy/_core/shape_base.py:367\u001b[39m, in \u001b[36mhstack\u001b[39m\u001b[34m(tup, dtype, casting)\u001b[39m\n\u001b[32m    365\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m _nx.concatenate(arrs, \u001b[32m0\u001b[39m, dtype=dtype, casting=casting)\n\u001b[32m    366\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m367\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_nx\u001b[49m\u001b[43m.\u001b[49m\u001b[43mconcatenate\u001b[49m\u001b[43m(\u001b[49m\u001b[43marrs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcasting\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcasting\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[31mValueError\u001b[39m: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 1 has size 3"
     ]
    }
   ],
   "source": [
    "np.hstack((a,b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "d09e402c",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 374
    },
    "id": "KZaBAqNFPgAW",
    "outputId": "388927a4-6e95-4e41-f7bb-080e841f2225"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 5., 1., 2.],\n",
       "       [2., 1., 2., 2.],\n",
       "       [5., 2., 6., 0.]])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hstack((b,d))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9382e062",
   "metadata": {},
   "source": [
    "- For `hstack()`, number of columns does not matter\n",
    "- Like `vstack()`, can combine a sequence of arrays"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "ce09b2d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7., 6., 4.],\n",
       "       [8., 1., 3.],\n",
       "       [9., 6., 3.]])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "e = np.floor(10*np.random.random((3,3)))\n",
    "e"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "a0e8cfe1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 5., 1., 2., 7., 6., 4.],\n",
       "       [2., 1., 2., 2., 8., 1., 3.],\n",
       "       [5., 2., 6., 0., 9., 6., 3.]])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hstack((b,d,e))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26e2bea0",
   "metadata": {
    "id": "w8kXeA-cPgAX"
   },
   "source": [
    "### Splitting arrays"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "19ece54b",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "IJWoNNByPgAX",
    "outputId": "4524b696-c4c3-4907-dab3-06d0c29c070a"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "       [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.floor(10*np.random.random((2,12)))\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10f6b98e",
   "metadata": {},
   "source": [
    "- `hsplit(A,n)` splits array `A` into `n` equal parts horizontally\n",
    "- `n` must be a divisor of the number of columns in `A`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "48d8d067",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Iuub4T1tPgAX",
    "outputId": "cbea1f4b-dd3a-4a01-f194-ce610b325636"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[1., 1., 6., 1.],\n",
       "        [0., 9., 3., 7.]]),\n",
       " array([[7., 2., 8., 1.],\n",
       "        [6., 7., 0., 2.]]),\n",
       " array([[4., 6., 4., 4.],\n",
       "        [0., 7., 9., 1.]])]"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hsplit(a,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "25666e7d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[1., 1.],\n",
       "        [0., 9.]]),\n",
       " array([[6., 1.],\n",
       "        [3., 7.]]),\n",
       " array([[7., 2.],\n",
       "        [6., 7.]]),\n",
       " array([[8., 1.],\n",
       "        [0., 2.]]),\n",
       " array([[4., 6.],\n",
       "        [0., 7.]]),\n",
       " array([[4., 4.],\n",
       "        [9., 1.]])]"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hsplit(a,6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "1a531ee0",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "array split does not result in an equal division",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[38]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mnp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mhsplit\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[32;43m5\u001b[39;49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m~/python-venv/lib/python3.13/site-packages/numpy/lib/_shape_base_impl.py:959\u001b[39m, in \u001b[36mhsplit\u001b[39m\u001b[34m(ary, indices_or_sections)\u001b[39m\n\u001b[32m    957\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m'\u001b[39m\u001b[33mhsplit only works on arrays of 1 or more dimensions\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m    958\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m ary.ndim > \u001b[32m1\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m959\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43msplit\u001b[49m\u001b[43m(\u001b[49m\u001b[43mary\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindices_or_sections\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m    960\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m    961\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m split(ary, indices_or_sections, \u001b[32m0\u001b[39m)\n",
      "\u001b[36mFile \u001b[39m\u001b[32m~/python-venv/lib/python3.13/site-packages/numpy/lib/_shape_base_impl.py:884\u001b[39m, in \u001b[36msplit\u001b[39m\u001b[34m(ary, indices_or_sections, axis)\u001b[39m\n\u001b[32m    882\u001b[39m     N = ary.shape[axis]\n\u001b[32m    883\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m N % sections:\n\u001b[32m--> \u001b[39m\u001b[32m884\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m    885\u001b[39m             \u001b[33m'\u001b[39m\u001b[33marray split does not result in an equal division\u001b[39m\u001b[33m'\u001b[39m) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m    886\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m array_split(ary, indices_or_sections, axis)\n",
      "\u001b[31mValueError\u001b[39m: array split does not result in an equal division"
     ]
    }
   ],
   "source": [
    "np.hsplit(a,5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d811e61d",
   "metadata": {},
   "source": [
    "- Can also specify where to split as a list of columns\n",
    "- `hsplit(A,[c1,c2,..,ck])` will split as `A[:c1]`,`A[c1:c2]`,...,`A[ck:]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "71a09d5f",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "B99x--gCPgAX",
    "outputId": "32298f0d-ee36-439a-de1e-553e6ba40b51"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[1., 1.],\n",
       "        [0., 9.]]),\n",
       " array([[6., 1., 7.],\n",
       "        [3., 7., 6.]]),\n",
       " array([[2., 8.],\n",
       "        [7., 0.]]),\n",
       " array([[1., 4., 6., 4., 4.],\n",
       "        [2., 0., 7., 9., 1.]])]"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hsplit(a,(2,5,7)) # a[:2], a[2:5], a[5:7], a[7:]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1d9956c",
   "metadata": {},
   "source": [
    "- Similarly, `vsplit` for vertical split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "382efea1",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "aiczUDZ7PgAX",
    "outputId": "75552879-cd4c-4906-b99c-4c68e28d6a35"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.]]),\n",
       " array([[0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]])]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vsplit(a,2) # Split a vertically"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "5c76cebe",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.]]),\n",
       " array([[0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]])]"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.split(a,2) # behaves like vsplit"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fa690b1",
   "metadata": {},
   "source": [
    "### Reshaping arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15c6d6e0",
   "metadata": {
    "id": "8MPOa8PnPgAZ"
   },
   "source": [
    "- Can change the *shape* of an array if the dimensions match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "164312a7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 12)"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "b1cea701-2565-49e8-9189-121819e38b39",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "       [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape = 2,12\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "3be27a7b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 1., 6., 1., 7., 2.],\n",
       "       [8., 1., 4., 6., 4., 4.],\n",
       "       [0., 9., 3., 7., 6., 7.],\n",
       "       [0., 2., 0., 7., 9., 1.]])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape = 4,6\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "954d26a5-dbfa-44d4-915e-22096ee55fc9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 1., 6., 1., 7., 2., 8., 1.],\n",
       "       [4., 6., 4., 4., 0., 9., 3., 7.],\n",
       "       [6., 7., 0., 2., 0., 7., 9., 1.]])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape = 3,8\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "162483a2-dcfc-4165-a120-2c1d6d4cfb99",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[1., 1., 6., 1.],\n",
       "        [7., 2., 8., 1.],\n",
       "        [4., 6., 4., 4.]],\n",
       "\n",
       "       [[0., 9., 3., 7.],\n",
       "        [6., 7., 0., 2.],\n",
       "        [0., 7., 9., 1.]]])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape = 2,3,4\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38c20710",
   "metadata": {
    "id": "CHDoUz0wPgAY"
   },
   "source": [
    "### Copy and view"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "19b4cef5",
   "metadata": {},
   "outputs": [],
   "source": [
    "a.shape = 2,12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "60c9a999",
   "metadata": {
    "id": "UdEup_87PgAY"
   },
   "outputs": [],
   "source": [
    "c = a.copy()  # Creates a disjoint copy of the array\n",
    "d = a.view()  # Creates another link to the same array\n",
    "e = a         # Aliases e to point to same array as a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "bb9b49f5",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "BOQNN1jmPgAY",
    "outputId": "f03caa0d-3f27-4b48-808c-137cb3ed22c4"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]),\n",
       " array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]),\n",
       " array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]),\n",
       " array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]))"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a, c, d, e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3f5a566",
   "metadata": {},
   "source": [
    "- Updating `c` has no effect on the others since it is a disjoint copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "5f7c5ed9",
   "metadata": {
    "id": "0fHh6aqrPgAY"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]),\n",
       " array([[1., 1., 6., 1., 7., 2., 8., 1., 4., 6., 4., 4.],\n",
       "        [0., 9., 3., 7., 6., 7., 0., 2., 0., 7., 9., 1.]]))"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c[0,4] = 88  # Note, not c[0][4]\n",
    "a, c, d, e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee3c613e",
   "metadata": {},
   "source": [
    "- Updating `d` will indirectly update `a` and `e`, but not `c`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "eb694ac9",
   "metadata": {
    "id": "qAyGiU5gPgAZ"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.,  1.,  7., 66.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d[0,5] = 66\n",
    "a, c, d, e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85affc3a",
   "metadata": {},
   "source": [
    "- Likewise, updating `e` updates `a` and `d`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "62617b80",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "e[0,6] = 77\n",
    "a, c, d, e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2c39372",
   "metadata": {},
   "source": [
    "- We can flatten an array into a sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "5253c9a4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.0 1.0 6.0 1.0 7.0 66.0 77.0 1.0 4.0 6.0 4.0 4.0 0.0 9.0 3.0 7.0 6.0 7.0 0.0 2.0 0.0 7.0 9.0 1.0 "
     ]
    }
   ],
   "source": [
    "for i in a.flat:\n",
    "    print(i,end=\" \")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d43d423",
   "metadata": {
    "id": "KCHfd3tHPgAZ"
   },
   "source": [
    "- `base` tells us if an array shares its storage with another array\n",
    "- For the original array, `base` is `None`\n",
    "- For a view, the `base` points to the \"parent\" array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "b5f32d56",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(None,\n",
       " None,\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " None)"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.base, c.base, d.base, e.base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "71b4d2a0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.base is a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3768d293",
   "metadata": {},
   "source": [
    "- Changing the shape of the base does array not affect the shape of a view"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "a34cbfcb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [ 0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [ 0.,  2.,  0.,  7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape = 4,6\n",
    "a,c,d,e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81c57a3d",
   "metadata": {},
   "source": [
    "- Changing the shape of the view does not affect the shape of the base array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "e7a31ce9",
   "metadata": {
    "id": "Z_b9L3OiPgAa"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [ 0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.],\n",
       "        [ 4.,  6.,  4.,  4.,  0.,  9.,  3.,  7.],\n",
       "        [ 6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [ 0.,  2.,  0.,  7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.shape = 3,8\n",
    "a,c,d,e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94eb247f",
   "metadata": {},
   "source": [
    "- Since they still have the same base, updating `a` changes the corresponding element in `d`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "23d94010",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [99.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.],\n",
       "        [ 4.,  6.,  4.,  4.,  0.,  9.,  3.,  7.],\n",
       "        [ 6.,  7., 99.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66.],\n",
       "        [77.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.],\n",
       "        [99.,  2.,  0.,  7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[3,0] = 99\n",
    "a,c,d,e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f21db46",
   "metadata": {},
   "source": [
    "- Likewise, updating the shape of `e`, which is an alias for `a`, does not affect the shape of the view `d`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "585b516c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  1.,  6.],\n",
       "        [ 1.,  7., 66.],\n",
       "        [77.,  1.,  4.],\n",
       "        [ 6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.],\n",
       "        [ 7.,  6.,  7.],\n",
       "        [99.,  2.,  0.],\n",
       "        [ 7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1., 88.,  2.,  8.,  1.,  4.,  6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.,  7.,  6.,  7.,  0.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.,  1.,  7., 66., 77.,  1.],\n",
       "        [ 4.,  6.,  4.,  4.,  0.,  9.,  3.,  7.],\n",
       "        [ 6.,  7., 99.,  2.,  0.,  7.,  9.,  1.]]),\n",
       " array([[ 1.,  1.,  6.],\n",
       "        [ 1.,  7., 66.],\n",
       "        [77.,  1.,  4.],\n",
       "        [ 6.,  4.,  4.],\n",
       "        [ 0.,  9.,  3.],\n",
       "        [ 7.,  6.,  7.],\n",
       "        [99.,  2.,  0.],\n",
       "        [ 7.,  9.,  1.]]))"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "e.shape = 8,3\n",
    "a,c,d,e"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecf831b0",
   "metadata": {},
   "source": [
    "### Matrix operations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "6f6f97c5",
   "metadata": {
    "id": "_tlORJR39JCX"
   },
   "outputs": [],
   "source": [
    "a = np.array([[1,2],[3,4]])\n",
    "b = np.array([[5,6],[7,8]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "66ab56e4",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "bf-JLWzy9WIQ",
    "outputId": "13ca520e-62f3-4c5f-ef98-803fa7980127"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[1, 2],\n",
       "        [3, 4]]),\n",
       " array([[5, 6],\n",
       "        [7, 8]]))"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a,b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80bd3924",
   "metadata": {},
   "source": [
    "- Pointwise addition and multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "ff0a7f36",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Nt22QeUt9YYx",
    "outputId": "2987cb3e-6b0e-4908-972e-71d8a1482020"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 6,  8],\n",
       "        [10, 12]]),\n",
       " array([[ 5, 12],\n",
       "        [21, 32]]))"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a+b, a*b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ba1475e",
   "metadata": {},
   "source": [
    "- Matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "1cea7471",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "ovbajxvGz7aD",
    "outputId": "f78ff2b2-658b-489a-d6ef-6d1cabe0d10e"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[19, 22],\n",
       "       [43, 50]])"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(a,b)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dff2f85a",
   "metadata": {},
   "source": [
    "- Transpose and inverse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "c3b3bf57",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "jjQ_aEei0FyO",
    "outputId": "616ca916-cf5b-4eec-812c-e05aa3e8b955"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 3],\n",
       "       [2, 4]])"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "ed0b0eba",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "6tAyxzKK0SVO",
    "outputId": "1049c3b7-e899-4e81-ed22-66845b88e0a3"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-2. ,  1. ],\n",
       "       [ 1.5, -0.5]])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linalg.inv(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d57fca4",
   "metadata": {},
   "source": [
    "- $A A^{-1}$ should give the identity matrix\n",
    "- Note the small imprecision due to round off error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "9e4a3736",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "DDf8EGtC0Y9w",
    "outputId": "8a51e4b8-bc71-4435-e9e3-65076495bfaa",
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.0000000e+00, 0.0000000e+00],\n",
       "       [8.8817842e-16, 1.0000000e+00]])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(a,np.linalg.inv(a)) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06b4917d",
   "metadata": {},
   "source": [
    "- Fit a function $f$ to a set of data points $\\{(x_1,y_1), (x_2,y_2), \\ldots, (x_n,y_n)\\}$\n",
    "- Compute *mean square error (MSE)*\n",
    "\n",
    "$\\displaystyle MSE = \\frac{1}{n} \\sum_{i=1}^{n} (f(x_i) - y_i)^2$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "9737ec0b",
   "metadata": {},
   "outputs": [],
   "source": [
    "predictions = np.array([1.2,2.3,3.1]) # (f(x1), f(x2), f(x3))\n",
    "values = np.array([1,2.5,3]) # (y1, y2, y3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "799ffa9b",
   "metadata": {},
   "source": [
    "- `predictions - values` creates the array $(f(x_1) - y_1, f(x_2) - y_2, f(x_3)-y_3)$\n",
    "- Applying `np.square` to this squares each element\n",
    "- Applying `np.sum` to the result sums up the squares of the errors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "6075b2f2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.03000000000000002)"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n = len(predictions)\n",
    "mse = 1/n * np.sum(np.square(predictions-values))\n",
    "mse"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58ef2f1f",
   "metadata": {},
   "source": [
    "### Axes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "fb40bf97",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.74535302, 7.32186747, 3.09968508],\n",
       "       [1.4351353 , 5.3403798 , 2.05243956],\n",
       "       [0.17113068, 2.72845255, 0.07238354],\n",
       "       [2.31854671, 6.79866632, 4.2397082 ]])"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.random.random((4,3))*10\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77d305dd",
   "metadata": {},
   "source": [
    "- `np.sum()` adds up all the entries in the array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "a82a6610",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(36.32374822114578)"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sum(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a948048",
   "metadata": {},
   "source": [
    "- Selecting `axis = 0` applies the operation column by column"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "0e1440e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 4.67016571, 22.18936614,  9.46421637])"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sum(a,axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "317949ff",
   "metadata": {},
   "source": [
    "- Selecting `axis = 1` applies the opertion row by row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "ea8a7dda",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([11.16690556,  8.82795466,  2.97196677, 13.35692123])"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sum(a,axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b81b7b94",
   "metadata": {},
   "source": [
    "- `concatenate()` generalizes `vstack()` and `hstack()`\n",
    "- By default it is `vstack()`, equivalent to setting `axis = 0`\n",
    "- If we set `axis = 1`, we get `hstack()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "5fa97c15",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[2.78302014, 7.96796426, 5.57485252],\n",
       "       [9.52754737, 8.00566296, 3.4566572 ],\n",
       "       [7.23662734, 3.12841927, 1.92923489],\n",
       "       [8.92895264, 3.02463578, 6.91495572]])"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.random.random((4,3))*10\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "ab2bd96a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0.74535302, 7.32186747, 3.09968508],\n",
       "        [1.4351353 , 5.3403798 , 2.05243956],\n",
       "        [0.17113068, 2.72845255, 0.07238354],\n",
       "        [2.31854671, 6.79866632, 4.2397082 ],\n",
       "        [2.78302014, 7.96796426, 5.57485252],\n",
       "        [9.52754737, 8.00566296, 3.4566572 ],\n",
       "        [7.23662734, 3.12841927, 1.92923489],\n",
       "        [8.92895264, 3.02463578, 6.91495572]]),\n",
       " array([[0.74535302, 7.32186747, 3.09968508, 2.78302014, 7.96796426,\n",
       "         5.57485252],\n",
       "        [1.4351353 , 5.3403798 , 2.05243956, 9.52754737, 8.00566296,\n",
       "         3.4566572 ],\n",
       "        [0.17113068, 2.72845255, 0.07238354, 7.23662734, 3.12841927,\n",
       "         1.92923489],\n",
       "        [2.31854671, 6.79866632, 4.2397082 , 8.92895264, 3.02463578,\n",
       "         6.91495572]]))"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack((a,b)), np.hstack((a,b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "51a6d38f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.74535302, 7.32186747, 3.09968508],\n",
       "       [1.4351353 , 5.3403798 , 2.05243956],\n",
       "       [0.17113068, 2.72845255, 0.07238354],\n",
       "       [2.31854671, 6.79866632, 4.2397082 ],\n",
       "       [2.78302014, 7.96796426, 5.57485252],\n",
       "       [9.52754737, 8.00566296, 3.4566572 ],\n",
       "       [7.23662734, 3.12841927, 1.92923489],\n",
       "       [8.92895264, 3.02463578, 6.91495572]])"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate((a,b))  # Implicitly, axis = 0, so vstack()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "51d291fa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.74535302, 7.32186747, 3.09968508, 2.78302014, 7.96796426,\n",
       "        5.57485252],\n",
       "       [1.4351353 , 5.3403798 , 2.05243956, 9.52754737, 8.00566296,\n",
       "        3.4566572 ],\n",
       "       [0.17113068, 2.72845255, 0.07238354, 7.23662734, 3.12841927,\n",
       "        1.92923489],\n",
       "       [2.31854671, 6.79866632, 4.2397082 , 8.92895264, 3.02463578,\n",
       "        6.91495572]])"
      ]
     },
     "execution_count": 76,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate((a,b),axis=1) # Concatenate row-wise, so same as hstack()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "1768c698",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0.77252961, 0.9476818 , 0.22204027, 0.11708873, 0.91664732,\n",
       "         0.35529799, 0.09111515]]),\n",
       " array([[0.3056627 , 0.83884962, 0.25602509, 0.06546634, 0.41950657,\n",
       "         0.73748701, 0.01506722]]))"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.random.random((1,7))\n",
    "d = np.random.random((1,7))\n",
    "c,d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "9a6b31cc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.77252961, 0.9476818 , 0.22204027, 0.11708873, 0.91664732,\n",
       "        0.35529799, 0.09111515, 0.3056627 , 0.83884962, 0.25602509,\n",
       "        0.06546634, 0.41950657, 0.73748701, 0.01506722]])"
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate((c,d),axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51391597",
   "metadata": {},
   "source": [
    "### Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c321b32",
   "metadata": {},
   "source": [
    "- Array with scalar --- map operation to each array element"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "6e667559",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2., 4., 6.])"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1.0, 2.0, 3.0])\n",
    "b = 2.0\n",
    "a * b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bace1b27",
   "metadata": {},
   "source": [
    "- Array with array/sequence of same length --- pointwise application of operation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "5ac721de",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2., 4., 6.])"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1.0, 2.0, 3.0])\n",
    "b = np.array([2.0, 2.0, 2.0])\n",
    "a * b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d9af900",
   "metadata": {},
   "source": [
    "- More generally, can broadcast to an array of same dimension as rightmost index\n",
    "\n",
    "*Example*\n",
    "\n",
    "- Store an $m \\times n$ image as 3 layers, Red, Blue and Green\n",
    "- Array dimensions are $(m,n,3)$\n",
    "- Want to scale RGB values by different amounts\n",
    "- Multiply image by $(rscale,bscale,gscale)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "40533355",
   "metadata": {},
   "outputs": [],
   "source": [
    "pic = np.random.random((4,4,3))*10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "ac57c8b3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[5.7448521 , 6.21715157, 8.09743372],\n",
       "        [3.86616619, 1.83400169, 3.30234273],\n",
       "        [7.14510501, 8.53592886, 0.1984932 ],\n",
       "        [2.83792466, 2.78075699, 6.47495444]],\n",
       "\n",
       "       [[4.20196209, 0.05568092, 9.82591891],\n",
       "        [7.88589042, 4.24747824, 1.91112919],\n",
       "        [6.23340351, 5.32555818, 8.30908835],\n",
       "        [0.10657329, 6.2069235 , 3.47629843]],\n",
       "\n",
       "       [[4.79882427, 0.91260498, 4.87367519],\n",
       "        [5.43909663, 9.33695084, 8.74619775],\n",
       "        [7.92382402, 0.32737941, 0.68173562],\n",
       "        [1.91816694, 3.49747929, 7.85137433]],\n",
       "\n",
       "       [[8.97653917, 4.78902054, 5.36404235],\n",
       "        [5.54700431, 9.70798109, 8.02925934],\n",
       "        [8.83133383, 0.98081094, 4.92779854],\n",
       "        [3.86833919, 4.14670514, 6.73500368]]])"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "d6e11e26",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[5.74485210e+00, 6.21715157e+02, 8.09743372e+03],\n",
       "        [3.86616619e+00, 1.83400169e+02, 3.30234273e+03],\n",
       "        [7.14510501e+00, 8.53592886e+02, 1.98493199e+02],\n",
       "        [2.83792466e+00, 2.78075699e+02, 6.47495444e+03]],\n",
       "\n",
       "       [[4.20196209e+00, 5.56809248e+00, 9.82591891e+03],\n",
       "        [7.88589042e+00, 4.24747824e+02, 1.91112919e+03],\n",
       "        [6.23340351e+00, 5.32555818e+02, 8.30908835e+03],\n",
       "        [1.06573294e-01, 6.20692350e+02, 3.47629843e+03]],\n",
       "\n",
       "       [[4.79882427e+00, 9.12604978e+01, 4.87367519e+03],\n",
       "        [5.43909663e+00, 9.33695084e+02, 8.74619775e+03],\n",
       "        [7.92382402e+00, 3.27379407e+01, 6.81735625e+02],\n",
       "        [1.91816694e+00, 3.49747929e+02, 7.85137433e+03]],\n",
       "\n",
       "       [[8.97653917e+00, 4.78902054e+02, 5.36404235e+03],\n",
       "        [5.54700431e+00, 9.70798109e+02, 8.02925934e+03],\n",
       "        [8.83133383e+00, 9.80810942e+01, 4.92779854e+03],\n",
       "        [3.86833919e+00, 4.14670514e+02, 6.73500368e+03]]])"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pic*[1,100,1000]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4c1fb26",
   "metadata": {},
   "source": [
    "*Note*\n",
    "- In the example above, a shape of `(3,4,4)` would display more intuitively as 3 layers of colour for the base image of shape `(4,4)`\n",
    "- However, for broadcasting, we need the *rightmost* index to match, so we wrote it as `(4,4,3)`, which is laid out less intuitively by `numpy` as 4 layers with shape `(4,3)`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26c11989",
   "metadata": {},
   "source": [
    "*Broadcasting example*\n",
    "\n",
    "- Find the nearest point to a given point in a collection\n",
    "- Given $(x,y)$ and $\\{(x_1,y_1), (x_2,y_2), \\ldots, (x_n,y_n)\\}$, report $j$ such that $(x_j,y_j)$ is the closest point to $(x,y)$\n",
    "- Distance of each point is $\\sqrt{(x_i - x)^2 + (y_i - y)^2}$\n",
    "- $\\arg\\min$ reports index where $\\min$ is achieved"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "812a8273",
   "metadata": {},
   "source": [
    "- Here is the whole computation in one shot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "7d27093c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([21.58703314, 17.49285568, 73.79024326, 56.04462508]), np.int64(1))"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "observation = np.array([111.0, 188.0])  # (x,y)\n",
    "codes = np.array([[132.0, 193.0],  # [(x1,y1), (x2,y2), (x3,y3), (x4,y4)]\n",
    "               [102.0, 203.0],\n",
    "               [45.0, 155.0],\n",
    "               [57.0, 173.0]])\n",
    "\n",
    "diff = codes - observation\n",
    "dist = np.sqrt(np.sum(diff**2,axis=1))\n",
    "dist, np.argmin(dist)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3754d683",
   "metadata": {},
   "source": [
    "- Let us break this up into steps"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87d1d6f5",
   "metadata": {},
   "source": [
    "1. The setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "89f299ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "observation = np.array([111.0, 188.0])  # (x,y)\n",
    "codes = np.array([[132.0, 193.0],  # [(x1,y1), (x2,y2), (x3,y3), (x4,y4)]\n",
    "               [102.0, 203.0],\n",
    "               [45.0, 155.0],\n",
    "               [57.0, 173.0]])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1f7d2c3",
   "metadata": {},
   "source": [
    "2. Use broadcast to subtact $(x,y)$ from each $(x_i,y_i)$ to get the array $[(x_1-x,y_1-y),(x_2-x,y_2-y),(x_3-x,y_3-y),(x_4-x,y_4-y)]$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "d9bc0821",
   "metadata": {},
   "outputs": [],
   "source": [
    "diff = codes - observation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "439413d2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 21.,   5.],\n",
       "       [ -9.,  15.],\n",
       "       [-66., -33.],\n",
       "       [-54., -15.]])"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88303d41",
   "metadata": {},
   "source": [
    "3. Use scalar broadcast to map each pair $(x_i-x,y_i-y)$ to $((x_i-x)^2,(y_i-y)^2)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "c9b04bd7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 441.,   25.],\n",
       "       [  81.,  225.],\n",
       "       [4356., 1089.],\n",
       "       [2916.,  225.]])"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff**2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7197808",
   "metadata": {},
   "source": [
    "4. Add up each row as $(x_i-x)^2 + (y_i-y)^2$ by computing `np.sum()` along `axis = 1`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "7daa8192",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 466.,  306., 5445., 3141.])"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sum(diff**2,axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7df0438b",
   "metadata": {},
   "source": [
    "5. Apply `np.sqrt()` pointwise to this array of squared differences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "aa845693",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([21.58703314, 17.49285568, 73.79024326, 56.04462508])"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(np.sum(diff**2,axis=1))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a660b0e",
   "metadata": {},
   "source": [
    "6. Find the index where this value is minimum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "c71bdf9a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(1)"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dist = np.sqrt(np.sum(diff**2,axis=1))\n",
    "np.argmin(dist)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc4ea620",
   "metadata": {},
   "source": [
    "- Or, equivalently, without the intermediate variable `dist`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "3149ba82",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(1)"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.argmin(np.sqrt(np.sum(diff**2,axis=1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55340923",
   "metadata": {},
   "source": [
    "- In fact, the entire computation can be written in one line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "fa6d6561",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.int64(1)"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.argmin(np.sqrt(np.sum((codes-observation)**2,axis=1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "d43f7353-b363-476d-acbc-721ccbd6b514",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(17.4928556845359)"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.min(np.sqrt(np.sum((codes-observation)**2,axis=1)))"
   ]
  }
 ],
 "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.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
