{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Loops and Looping\n",
    "\n",
    "To get into real programming we have to look at loops; here we have a\n",
    "*block* of code that is repeated either a set number of times (`for` loops) *or* until some condition is reached (`while` loops).\n",
    "\n",
    "#### Key Point\n",
    "The use of *loops* can often be a significant hurdle for new\n",
    "programmers but it is absolutely key to programming. Any “non-trivial”\n",
    "program contains loops, often many of them, and is the key to a\n",
    "computer’s main strength of “doing the same simple thing over and over\n",
    "again…” very fast.\n",
    "\n",
    "\n",
    "## Fixed length loops\n",
    "\n",
    "First we will start with the simplest case of fixed length loops. Assume\n",
    "we want to print out values of $\\cos(\\theta)$ in the range\n",
    "$0\\rightarrow2\\pi$ using a `for` loop. Consider the piece of code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "theta is : 0.0 cos(theta) : 1.0\n",
      "theta is : 0.12566370614359174 cos(theta) : 0.9921147013144779\n",
      "theta is : 0.25132741228718347 cos(theta) : 0.9685831611286311\n",
      "theta is : 0.3769911184307752 cos(theta) : 0.9297764858882513\n",
      "theta is : 0.5026548245743669 cos(theta) : 0.8763066800438636\n",
      "theta is : 0.6283185307179586 cos(theta) : 0.8090169943749475\n",
      "theta is : 0.7539822368615504 cos(theta) : 0.7289686274214116\n",
      "theta is : 0.8796459430051422 cos(theta) : 0.6374239897486896\n",
      "theta is : 1.0053096491487339 cos(theta) : 0.5358267949789965\n",
      "theta is : 1.1309733552923256 cos(theta) : 0.42577929156507266\n",
      "theta is : 1.2566370614359172 cos(theta) : 0.30901699437494745\n",
      "theta is : 1.3823007675795091 cos(theta) : 0.18738131458572452\n",
      "theta is : 1.5079644737231008 cos(theta) : 0.0627905195293133\n",
      "theta is : 1.6336281798666925 cos(theta) : -0.0627905195293134\n",
      "theta is : 1.7592918860102844 cos(theta) : -0.18738131458572482\n",
      "theta is : 1.884955592153876 cos(theta) : -0.30901699437494756\n",
      "theta is : 2.0106192982974678 cos(theta) : -0.4257792915650727\n",
      "theta is : 2.1362830044410597 cos(theta) : -0.5358267949789969\n",
      "theta is : 2.261946710584651 cos(theta) : -0.6374239897486897\n",
      "theta is : 2.387610416728243 cos(theta) : -0.7289686274214117\n",
      "theta is : 2.5132741228718345 cos(theta) : -0.8090169943749473\n",
      "theta is : 2.6389378290154264 cos(theta) : -0.8763066800438636\n",
      "theta is : 2.7646015351590183 cos(theta) : -0.9297764858882515\n",
      "theta is : 2.8902652413026098 cos(theta) : -0.9685831611286311\n",
      "theta is : 3.0159289474462017 cos(theta) : -0.9921147013144779\n",
      "theta is : 3.1415926535897936 cos(theta) : -1.0\n",
      "theta is : 3.267256359733385 cos(theta) : -0.9921147013144779\n",
      "theta is : 3.392920065876977 cos(theta) : -0.9685831611286311\n",
      "theta is : 3.518583772020569 cos(theta) : -0.9297764858882512\n",
      "theta is : 3.6442474781641603 cos(theta) : -0.8763066800438635\n",
      "theta is : 3.769911184307752 cos(theta) : -0.8090169943749472\n",
      "theta is : 3.8955748904513436 cos(theta) : -0.7289686274214116\n",
      "theta is : 4.0212385965949355 cos(theta) : -0.6374239897486895\n",
      "theta is : 4.1469023027385274 cos(theta) : -0.5358267949789963\n",
      "theta is : 4.272566008882119 cos(theta) : -0.42577929156507216\n",
      "theta is : 4.39822971502571 cos(theta) : -0.30901699437494756\n",
      "theta is : 4.523893421169302 cos(theta) : -0.18738131458572463\n",
      "theta is : 4.649557127312894 cos(theta) : -0.06279051952931321\n",
      "theta is : 4.775220833456486 cos(theta) : 0.06279051952931372\n",
      "theta is : 4.900884539600078 cos(theta) : 0.18738131458572513\n",
      "theta is : 5.026548245743669 cos(theta) : 0.30901699437494723\n",
      "theta is : 5.152211951887261 cos(theta) : 0.4257792915650726\n",
      "theta is : 5.277875658030853 cos(theta) : 0.5358267949789968\n",
      "theta is : 5.403539364174445 cos(theta) : 0.63742398974869\n",
      "theta is : 5.529203070318037 cos(theta) : 0.7289686274214119\n",
      "theta is : 5.6548667764616285 cos(theta) : 0.8090169943749478\n",
      "theta is : 5.7805304826052195 cos(theta) : 0.8763066800438636\n",
      "theta is : 5.906194188748811 cos(theta) : 0.9297764858882515\n",
      "theta is : 6.031857894892403 cos(theta) : 0.9685831611286312\n",
      "theta is : 6.157521601035995 cos(theta) : 0.9921147013144779\n",
      "End of loop\n"
     ]
    }
   ],
   "source": [
    "import math \n",
    "\n",
    "points = 50 \n",
    "dt = 2.0*math.pi/points \n",
    "for i in range(0,points): \n",
    "    theta = dt*i \n",
    "    value = math.cos(theta) \n",
    "    print(\"theta is : \" + str(theta) + \" cos(theta) : \" + str(value)) \n",
    "print(\"End of loop\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Looking at this in detail:\n",
    "\n",
    "-   Line 1: `points` is an `int`, in this case the number of points we want to calculate in between $0\\rightarrow2\\pi$\n",
    "\n",
    "-   Line 2: is the separation between each value of $\\theta$ we wish to\n",
    "    calculate.\n",
    "\n",
    "-   Line 3: the start of the `for` loop. It says: create an `int` variable `i` and while it is the range $0\\rightarrow49$, execute the loop:\n",
    "\n",
    "    -   It will *stop* before 50, so at 49.\n",
    "\n",
    "    -   The `:` at the end of the line is essential and is part of the\n",
    "        syntax.\n",
    "\n",
    ">    #### Range function \n",
    "The range function has the full syntax\n",
    "```python\n",
    "    range(start,end,step)\n",
    "```\n",
    "where `start` is the starting integer, `end` the termination integer and the *optional* argument `step` the amount the value is incremented each time. If `step` is not given, it defaults to 1.\n",
    "\n",
    ">    All arguments *must* be `int`, and the loop will terminate *before*\n",
    "    reaching the `end` value.\n",
    "\n",
    "-   Line 4 to 6: the indented code is *inside* the loop:\n",
    "\n",
    "    -   Calculate $\\theta$ by scaling `i` where `dt` is the separation between values.\n",
    "\n",
    "    -   Calculate `value`, being $\\cos(\\theta)$.\n",
    "\n",
    "    -   Print out the value of $\\theta$ and of $\\cos(\\theta)$ to the\n",
    "        screen.\n",
    "\n",
    "    It will do this 50 times.\n",
    "\n",
    "-   Line 7: Print `End of Loop` when the loop is finished; it will only print this\n",
    "    once.\n",
    "\n",
    "### Key Point\n",
    "Note the most important bits of syntax here are\n",
    "\n",
    "-   that the body of the loop, (lines 4,5, & 6), *must* be indented by\n",
    "    *exactly 4 spaces*.\n",
    "\n",
    "-   the loop variable `int` in that is automatically incremented each time round the loop.\n",
    "\n",
    "-   that the number of times the loop is exected is determined at the\n",
    "    start (even if the loop variable in changed within the body of the\n",
    "    loop).\n",
    "    \n",
    "## Loop access of lists\n",
    "\n",
    "One of the main applications of loops is to access the elements of a\n",
    "list, here we will look at two routes, the first conceptually simpler.\n",
    "\n",
    "Assume that the list `mydata` contains `float`s, its length is given by `len(mydata)` so if we want to sum up the values squared of the elements in `mydata` we could write"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'mydata' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-2-3cb76652cfbb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mtotal\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmydata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m     \u001b[0mtotal\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtotal\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mmydata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"The total of mydata squared is : \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtotal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'mydata' is not defined"
     ]
    }
   ],
   "source": [
    "total = 0.0 \n",
    "for i in range(0,len(mydata)): \n",
    "    total = total + mydata[i]**2\n",
    "\n",
    "print(\"The total of mydata squared is : \" + str(total))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "which in detail does the following:\n",
    "\n",
    "-   Line 1: create a variable `total` and set its initial value to zero.\n",
    "\n",
    "-   Line 2: start of loop from 0 to `len()` of list; note again `i` will run from $0\\rightarrow {\\tt len()} - 1$\n",
    "\n",
    "-   Line 3: add the square of the `i`th elements of `mydata` to `total`; note the indentation.\n",
    "\n",
    "-   Line 5: at the end of the loop print out the answer.\n",
    "\n",
    "> #### Missing Line 4\n",
    "Here Line 4 is *intentionally left blank*, you can insert extra blank lines anywhere in your code and leaving a blank line at the end of a loop makes the code more readable and easier to understand.\n",
    "\n",
    "> Remember: white-space is *free*, use it to make your code readable, it will save you much time and effort when trying to find bugs.\n",
    "\n",
    "### Key Point\n",
    "Here again the key points of this loop are\n",
    "\n",
    "-   the number of times the loop is executed is determined as the start,\n",
    "    it is `len(mydata)`.\n",
    "\n",
    "-   the loop index `i` is automatically incremented by $+1$ every time round the loop.\n",
    "\n",
    "-   the largest value that `i` takes is $len(mydata)-1$ which is the index of the *last* element in the list.\n",
    "\n",
    "However since accessing lists like this is such a common operation there\n",
    "is a more compact syntax to do the same thing; take the following piece\n",
    "of code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "total = 0.0 \n",
    "for d in mydata: \n",
    "    total = total + d*d\n",
    "\n",
    "print(\"The total of mydata squared is : \" + str(total))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "-   Line 1: create variable `total` and set it to zero.\n",
    "\n",
    "-   Line 2: start of `for` loop, here the variable `d` is set to the value of each of the elements of `mydata` in turn.\n",
    "\n",
    "-   Line 3: add the value of `d` squared to `total`.\n",
    "\n",
    "-   Line 5: at the end of the loop, print out the final value.\n",
    "\n",
    "Both of these pieces of code will do the same thing, but the second is\n",
    "shorter, more computationally efficient and in `Python` style, but somewhat more difficult to understand.\n",
    "\n",
    "> #### Being Pythonic \n",
    "Being “Pythonic” is a statement you will find all over\n",
    "the web; it means doing something in “python style” which usually means\n",
    "using a programming method or syntax unique to `Python` that is not available in other languages. This can be “good” as in the alternative method to access lists since it is shorter and more efficient, but can also be “bad” since some of the Pythonic style is very compact and difficult to work out what it is actually doing. It is also often used to push style over function.\n",
    "\n",
    "> You will find must heated *debate* about this on the computing forums\n",
    "often by people who’s knowledge is questionable, but you should\n",
    "concentrate on getting your programs to work and understand what they\n",
    "are doing first. Worry about making them “Pythonic” as you gain\n",
    "experience. Do NOT copy down “magic recipes” from forums that you don’t\n",
    "understand and may not do what you want / expect.\n",
    "\n",
    "\n",
    "## The `while` loop\n",
    "\n",
    "The other looping construct is when at the start of the loop we **do not\n",
    "know** how many times the loop is to be executed, for example consider\n",
    "the code below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'random' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-4-cbfe5d858a1f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m100\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Final value of x is : \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'random' is not defined"
     ]
    }
   ],
   "source": [
    "x = 0 \n",
    "while x < 100 : \n",
    "    x = x + random.randint(1,6)\n",
    "\n",
    "print(\"Final value of x is : \" + str(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "so looking at this in detail,\n",
    "\n",
    "-   Line 1: set the initial value of `x`\n",
    "\n",
    "-   Line 2: start of `while` loop, the body of the loop will be executed while the logical statement $x < 100$ is `True`\n",
    "\n",
    "In this type of loop the programmer is responsible for updating the\n",
    "termination condition, the `x` in this case. This type of loop is most often used in iterative methods, for example calculating the roots of an\n",
    "equation to a particular accuracy or the position of projectile.\n",
    "\n",
    "This type of loop is the key to solving Checkpont 5 in a couple of\n",
    "weeks.\n",
    "\n",
    "> #### Getting stuck \n",
    "The “danger” of the `while` loops is forgetting to update the\n",
    "variable that control the termination condition. The loop then never\n",
    "terminates and the program “hangs” going round-and-round “for ever”. If\n",
    "(when) this happens\n",
    "-   Type `Cntl-C` (both keys at once) which will interrupt the program and     tell you where it was in the code.\n",
    "-   If you can’t see the problem, print out the termination variable in\n",
    "    the loop to see what is happening.\n",
    "\n",
    "\n",
    "## The `break` statement\n",
    "\n",
    "An important concept associated with loops is the ability to “break out\n",
    "off a loop early”, which overrides the normal loop termination\n",
    "condition, so for example we could have:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-6-cb0d11525ce0>, line 3)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-6-cb0d11525ce0>\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m    x = <function that sets x>\u001b[0m\n\u001b[0m        ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "total = 0 \n",
    "while total < 100 : \n",
    "    x = <function that sets x> \n",
    "    if x < 0 :\n",
    "        break \n",
    "    else : \n",
    "        total = total + x\n",
    "\n",
    "print(\"End of loop\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "so in detail\n",
    "\n",
    "-   Line 1: set `total` to zero\n",
    "\n",
    "-   Line 2: start of `while` loop, which should run until $total < 100$\n",
    "\n",
    "-   Line 3: code that calculates a value for `x`\n",
    "\n",
    "-   Line 4 & 5: Tests if the value of `x` is negative, and if it is `break` the loop, so jump straight to the end of the loop *now*.\n",
    "\n",
    "-   Line 6 & 7: if `x` is positive, then add to `total` and continue with the loop.\n",
    "\n",
    "You should use the `break` statement with care; its proper use is to catch errors or unexpected conditions. Using it as a part of algorithm often results in code that is hard to read.\n",
    "\n",
    "A common programming *trick* is to deliberately put a program into an\n",
    "infinite loop and then use the `break` statement as the exit, for example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "while True : \n",
    "    x = \\<function to set x> \n",
    "    if x > 100: \n",
    "        break\n",
    "\n",
    "print(\"End of loop\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "8dd67a17",
   "metadata": {},
   "source": [
    "Here the `while` loop will run *forever* and your program will only exit this loop when `x` has been set to 100 (or more).\n",
    "\n",
    "This is a construct that is often used in interactive programs that keep\n",
    "taking “command” for example keeps asking for files to process or\n",
    "programs with a “graphical user interface” (GUI), but should be used\n",
    "with care in general programming since it difficult to debug and work\n",
    "out what is really happening.\n",
    "\n",
    "> **Code Examples**\n",
    "-   Loop to terminal using for range : [RangeLoop](../CodeExamples/RangeLoop.ipynb)\n",
    "-   Loop to list using for range : [RangeLooptoList](../CodeExamples/RangeLooptoList.ipynb)\n",
    "-   Loop to list using while : [WhileLooptoList](../CodeExamples/WhileLooptoList.ipynb)\n",
    "-   Guessing Game using `while` and `break`: [GuessGame](../CodeExamples/GuessGame.ipynb)\n",
    "\n",
    "> You should have a look at these examples and \"play\" with them."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}