{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": [
     "remove_input"
    ]
   },
   "outputs": [],
   "source": [
    "path_data = '../../data/'\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ranges\n",
    "\n",
    "A *range* is an array of numbers in increasing or decreasing order, each separated by a regular interval. \n",
    "Ranges are useful in a surprisingly large number of situations, so it's worthwhile to learn about them.\n",
    "\n",
    "Ranges are defined  using the `np.arange` function, which takes either one, two, or three arguments: a start, and end, and a 'step'.\n",
    "\n",
    "If you pass one argument to `np.arange`, this becomes the `end` value, with `start=0`, `step=1` assumed.  Two arguments give the `start` and `end` with `step=1` assumed.  Three arguments give the `start`, `end` and `step` explicitly.\n",
    "\n",
    "A range always includes its `start` value, but does not include its `end` value.  It counts up by `step`, and it stops before it gets to the `end`.\n",
    "\n",
    "    np.arange(end): An array starting with 0 of increasing consecutive integers, stopping before end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice how the array starts at 0 and goes only up to 4, not to the end value of 5."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "    np.arange(start, end): An array of consecutive increasing integers from start, stopping before end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3, 4, 5, 6, 7, 8])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(3, 9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "    np.arange(start, end, step): A range with a difference of step between each pair of consecutive values, starting from start and stopping before end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3,  8, 13, 18, 23, 28])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(3, 30, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This array starts at 3, then takes a step of 5 to get to 8, then another step of 5 to get to 13, and so on.\n",
    "\n",
    "When you specify a step, the start, end, and step can all be either positive or negative and may be whole numbers or fractions. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.5,  1. ,  0.5,  0. , -0.5, -1. , -1.5])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(1.5, -2, -0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example: Leibniz's formula for $\\pi$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The great German mathematician and philosopher [Gottfried Wilhelm Leibniz](https://en.wikipedia.org/wiki/Gottfried_Wilhelm_Leibniz) \n",
    "(1646 - 1716) discovered a wonderful formula for $\\pi$ as an infinite sum of simple fractions. The formula is\n",
    "\n",
    "$$\\pi = 4 \\cdot \\left(1 - \\frac{1}{3} + \\frac{1}{5} - \\frac{1}{7} + \\frac{1}{9} - \\frac{1}{11} + \\dots\\right)$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Though some math is needed to establish this, we can use arrays to convince ourselves that the formula works. Let's calculate the first 5000 terms of Leibniz's infinite sum and see if it is close to $\\pi$.\n",
    "\n",
    "$$4 \\cdot \\left(1 - \\frac{1}{3} + \\frac{1}{5} - \\frac{1}{7} + \\frac{1}{9} - \\frac{1}{11} + \\dots - \\frac{1}{9999} \\right)$$\n",
    "\n",
    "We will calculate this finite sum by adding all the positive terms first and then subtracting the sum of all the negative terms [[1]](#footnotes):\n",
    "\n",
    "$$4 \\cdot \\left( \\left(1 + \\frac{1}{5} + \\frac{1}{9} + \\dots + \\frac{1}{9997} \\right) - \\left(\\frac{1}{3} + \\frac{1}{7} + \\frac{1}{11} + \\dots + \\frac{1}{9999} \\right) \\right)$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The positive terms in the sum have 1, 5, 9, and so on in the denominators. The array `by_four_to_20` contains these numbers up to 17:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1,  5,  9, 13, 17])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "by_four_to_20 = np.arange(1, 20, 4)\n",
    "by_four_to_20"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get an accurate approximation to $\\pi$, we'll use the much longer array `positive_term_denominators`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([   1,    5,    9, ..., 9989, 9993, 9997])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "positive_term_denominators = np.arange(1, 10000, 4)\n",
    "positive_term_denominators"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The positive terms we actually want to add together are just 1 over these denominators:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "positive_terms = 1 / positive_term_denominators"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The negative terms have 3, 7, 11, and so on on in their denominators. This array is just 2 added to `positive_term_denominators`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "negative_terms = 1 / (positive_term_denominators + 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The overall sum is"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.1413926535917955"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "4 * ( sum(positive_terms) - sum(negative_terms) )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is very close to $\\pi = 3.14159\\dots$. Leibniz's formula is looking good!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='footnotes'></a>\n",
    "### Footnotes\n",
    "[1] Surprisingly, when we add  *infinitely* many fractions, the order can matter! But our approximation to $\\pi$ uses only a large finite number of fractions, so it's okay to add the terms in any convenient order."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
