diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..763513e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.ipynb_checkpoints
diff --git a/DefensiveProgramming.ipynb b/DefensiveProgramming.ipynb
new file mode 100644
index 0000000..d3655ec
--- /dev/null
+++ b/DefensiveProgramming.ipynb
@@ -0,0 +1,143 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " # Defensive programming (1)\n",
+ " \n",
+ " How much time do you spend writing software? How much time do you spend \n",
+ " debugging that software? It turns out that it is very easy to spend lots\n",
+ " of time fixing bugs and less time than you would like writing new software\n",
+ " to do new science. This is a problem that is fairly well understood by\n",
+ " the software engineering community, but many scientists don't take advantage \n",
+ " of this knowledge. This afternoon we will take a brief look at some of the \n",
+ " tools and technique to make your debugging less painful.\n",
+ " \n",
+ " We'll also think a bit about how you may know if your programmes are correct. \n",
+ " This is a much harder but important problem. Even minor errors in research \n",
+ " code can lead to the retraction of papers, as happened to Geoffrey Chang \n",
+ " in 2006 (see http://dx.doi.org/10.1126/science.314.5807.1856). Chang did\n",
+ " nothing malicious and committed no fraud, but because of a minor software \n",
+ " error had two retract five papers just before Christmas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "__NB: This notebook is designed for teaching about exceptions and error testing. It includes deliberate errors. There are probably accidental errors too.__"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Mean cell volume \n",
+ "First, we will look at how one programme can produce \n",
+ "the wrong answer, and how we can avoid this happening\n",
+ "when we use it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def cell_volume(X, Y, Z):\n",
+ " # Return the volume of a unit cell \n",
+ " # described by lattice vectors X, Y and Z\n",
+ " # The volume is given by the determinant of\n",
+ " # the matrix formed by sticking the three \n",
+ " # vectors together. i.e.\n",
+ " #\n",
+ " # | X[0] Y[0] Z[0] |\n",
+ " # V = | X[1] Y[1] Z[1] |\n",
+ " # | X[2] Y[2] Z[2] |\n",
+ " #\n",
+ " # V = X[0].Y[1].Z[2] + Y[0].Z[1].X[2] \n",
+ " # + X[2].Y[0].Z[1] - Z[0].Y[1].X[2]\n",
+ " # - Y[0].X[1].Z[2] - X[0].Z[1].Y[2]\n",
+ " \n",
+ " volume = (X[0]*Y[1]*Z[2] + Y[0]*Z[1]*X[2] + X[2]*Y[0]*Z[1] \n",
+ " - Z[0]*Y[1]*X[2] - Y[0]*X[1]*Z[2] - X[0]*Z[1]*Y[2])\n",
+ " \n",
+ " return volume"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def mean_cell_volume(cell_list):\n",
+ " # Return the avarage volume of a list \n",
+ " # of unit cells. Each element of cell_list\n",
+ " # should be a list of three lattice vectors, \n",
+ " # each with three components. The volume of\n",
+ " # each cell is calculated and summed before \n",
+ " # being devided by the number of cells to give\n",
+ " # the mean volume.\n",
+ " \n",
+ " num_cells = 0\n",
+ " sum_volume = 0.0\n",
+ " for cell in cell_list:\n",
+ " X = cell[0]\n",
+ " Y = cell[1]\n",
+ " Z = cell[2]\n",
+ " sum_volume = sum_volume + cell_volume(X, Y, Z)\n",
+ " num_cells = num_cells + 1\n",
+ " \n",
+ " mean_volume = sum_volume/num_cells\n",
+ " \n",
+ " return mean_volume\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 2",
+ "language": "python",
+ "name": "python2"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/DefensiveProgramming_2.ipynb b/DefensiveProgramming_2.ipynb
new file mode 100644
index 0000000..85afd4b
--- /dev/null
+++ b/DefensiveProgramming_2.ipynb
@@ -0,0 +1,82 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " # Defensive programming (2)\n",
+ " We have seen the basic idea that we can insert\n",
+ " assert statments into code, to check that the \n",
+ " results are what we expect, but how can we test\n",
+ " software more fully? Can doing this help us \n",
+ " avoid bugs in the first place?\n",
+ " \n",
+ " One possible approach is **test driven development**.\n",
+ " Many people think this reduces the number of bugs in \n",
+ " software as it is written, but evidence for this in the \n",
+ " sciences is somewhat limited as it is not always easy \n",
+ " to say what the right answer should be before writing the\n",
+ " software. Having said that, the tests involved in test\n",
+ " driven development are certanly useful even if some of\n",
+ " them are written after the software.\n",
+ " \n",
+ " We will look at a new (and quite difficult) problem, \n",
+ " finding the overlap between ranges of numbers. For \n",
+ " example, these could be the dates that different \n",
+ " sensors were running, and you need to find the \n",
+ " date ranges where all sensors recorded data before\n",
+ " running further analysis."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Start off by imagining you have a working function `range_overlap` that takes\n",
+ "a list of tuples. Write some assert statments that would check if the answer from this\n",
+ "function is correct. Put these in a function. Think of different cases and \n",
+ "about edge cases (which may show a subtle bug)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def test_range_overlap():\n",
+ " "
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 2",
+ "language": "python",
+ "name": "python2"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/notes/DefensiveProgrammingNotes.ipynb b/notes/DefensiveProgrammingNotes.ipynb
new file mode 100644
index 0000000..f3fa3c7
--- /dev/null
+++ b/notes/DefensiveProgrammingNotes.ipynb
@@ -0,0 +1,575 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " # Defensive programming (1)\n",
+ " \n",
+ " How much time do you spend writing software? How much time do you spend \n",
+ " debugging that software? It turns out that it is very easy to spend lots\n",
+ " of time fixing bugs and less time than you would like writing new software\n",
+ " to do new science. This is a problem that is fairly well understood by\n",
+ " the software engineering community, but many scientists don't take advantage \n",
+ " of this knowledge. This afternoon we will take a brief look at some of the \n",
+ " tools and technique to make your debugging less painful.\n",
+ " \n",
+ " We'll also think a bit about how you may know if your programmes are correct. \n",
+ " This is a much harder but important problem. Even minor errors in research \n",
+ " code can lead to the retraction of papers, as happened to Geoffrey Chang \n",
+ " in 2006 (see http://dx.doi.org/10.1126/science.314.5807.1856). Chang did\n",
+ " nothing malicious and committed no fraud, but because of a minor software \n",
+ " error had two retract five papers just before Christmas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "__NB: This notebook is designed for teaching about exceptions and error testing. It includes deliberate errors. There are probably accidental errors too.__"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Mean cell volume \n",
+ "First, we will look at how one programme can produce \n",
+ "the wrong answer, and how we can avoid this happening\n",
+ "when we use it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def cell_volume(X, Y, Z):\n",
+ " # Return the volume of a unit cell \n",
+ " # described by lattice vectors X, Y and Z\n",
+ " # The volume is given by the determinant of\n",
+ " # the matrix formed by sticking the three \n",
+ " # vectors together. i.e.\n",
+ " #\n",
+ " # | X[0] Y[0] Z[0] |\n",
+ " # V = | X[1] Y[1] Z[1] |\n",
+ " # | X[2] Y[2] Z[2] |\n",
+ " #\n",
+ " # V = X[0].Y[1].Z[2] + Y[0].Z[1].X[2] \n",
+ " # + X[2].Y[0].Z[1] - Z[0].Y[1].X[2]\n",
+ " # - Y[0].X[1].Z[2] - X[0].Z[1].Y[2]\n",
+ " \n",
+ " volume = (X[0]*Y[1]*Z[2] + Y[0]*Z[1]*X[2] + X[2]*Y[0]*Z[1] \n",
+ " - Z[0]*Y[1]*X[2] - Y[0]*X[1]*Z[2] - X[0]*Z[1]*Y[2])\n",
+ " \n",
+ " return volume"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "240.0"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cell_volume([4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def mean_cell_volume(cell_list):\n",
+ " # Return the avarage volume of a list \n",
+ " # of unit cells. Each element of cell_list\n",
+ " # should be a list of three lattice vectors, \n",
+ " # each with three components. The volume of\n",
+ " # each cell is calculated and summed before \n",
+ " # being devided by the number of cells to give\n",
+ " # the mean volume.\n",
+ " \n",
+ " num_cells = 0\n",
+ " sum_volume = 0.0\n",
+ " for cell in cell_list:\n",
+ " X = cell[0]\n",
+ " Y = cell[1]\n",
+ " Z = cell[2]\n",
+ " sum_volume = sum_volume + cell_volume(X, Y, Z)\n",
+ " num_cells = num_cells + 1\n",
+ " \n",
+ " mean_volume = sum_volume/num_cells\n",
+ " \n",
+ " return mean_volume\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "240.0"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[10.0, 0.0, 0.0], [0.0, 4.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[6.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 4.0]]])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "###\"Wrong\" input"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "IndexError",
+ "evalue": "list index out of range",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n\u001b[1;32m 2\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m10.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\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;32m----> 3\u001b[0;31m [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]]])\n\u001b[0m",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mmean_cell_volume\u001b[0;34m(cell_list)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mY\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mZ\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell\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[0;32m---> 16\u001b[0;31m \u001b[0msum_volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum_volume\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mcell_volume\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mY\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mZ\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mcell_volume\u001b[0;34m(X, Y, Z)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m volume = (X[0]*Y[1]*Z[2] + Y[0]*Z[1]*X[2] + X[2]*Y[0]*Z[1] \n\u001b[0;32m---> 17\u001b[0;31m - Z[0]*Y[1]*X[2] - Y[0]*X[1]*Z[2] - X[0]*Z[1]*Y[2])\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mIndexError\u001b[0m: list index out of range"
+ ]
+ }
+ ],
+ "source": [
+ "mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0]],\n",
+ " [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]]])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "ZeroDivisionError",
+ "evalue": "float division by zero",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmean_cell_volume\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[0;32m\u001b[0m in \u001b[0;36mmean_cell_volume\u001b[0;34m(cell_list)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0mmean_volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum_volume\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mnum_cells\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmean_volume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mZeroDivisionError\u001b[0m: float division by zero"
+ ]
+ }
+ ],
+ "source": [
+ "mean_cell_volume([])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### What is python telling us?\n",
+ "That something went wrong, where it went wrong, what went\n",
+ "wrong, and what the programme was doing at the time. This\n",
+ "is an exception.\n",
+ "\n",
+ "* Exception class (e.g `ZeroDivisionError`)\n",
+ "* Some further information (e.g. `float division by zero`)\n",
+ "* File (or cell) name and line number of each function in the call stack (e.g. in `mean_cell_volume` at line `---> 19` inside cell `ipython-input-...`)\n",
+ "\n",
+ "We can create these ourselves when we run code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "Exception",
+ "evalue": "something went wrong",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"something went wrong\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mException\u001b[0m: something went wrong"
+ ]
+ }
+ ],
+ "source": [
+ "raise Exception(\"something went wrong\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### What if we get the wrong answer?\n",
+ "This is a more difficult problem to spot - the avarage volume cannot be 0.0!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0.0"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[-4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[-4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]]])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The reason is that there is a bug in `cell_volume`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-240.0"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cell_volume([4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The volume should always be positive. We can check for this. This kind of check is known as an assertion."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "AssertionError",
+ "evalue": "The volume must be positive",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mvolume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell_volume\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m10.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mvolume\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0.0\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[0;32mraise\u001b[0m \u001b[0mAssertionError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"The volume must be positive\"\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;32mprint\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mAssertionError\u001b[0m: The volume must be positive"
+ ]
+ }
+ ],
+ "source": [
+ "volume = cell_volume([4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0])\n",
+ "if (volume < 0.0):\n",
+ " raise AssertionError(\"The volume must be positive\")\n",
+ "print volume"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can write these more easily with the **assert** statment. It is \n",
+ "good practice to put these in your code when you write it (and you \n",
+ "know what it does, and what assumptions you have made). These act \n",
+ "as a form of documentation as well as a form of protection. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "AssertionError",
+ "evalue": "The volume must be positive",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mvolume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell_volume\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m10.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mvolume\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"The volume must be positive\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mAssertionError\u001b[0m: The volume must be positive"
+ ]
+ }
+ ],
+ "source": [
+ "volume = cell_volume([4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0])\n",
+ "assert volume >= 0.0, \"The volume must be positive\"\n",
+ "print volume"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can think about three types of assert statment:\n",
+ "\n",
+ "* **precondition** - something that must be true at \n",
+ "the start of a function in order for it to work correctly.\n",
+ "\n",
+ "* **invariant** - something that is always true at a \n",
+ "particular point inside a piece of code.\n",
+ "\n",
+ "* **postcondition** - something that the function guarantees is true when it finishes.\n",
+ "\n",
+ "Lets think of some and add these to the functions above. My collection is inserted below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def cell_volume(X, Y, Z):\n",
+ " # Return the volume of a unit cell \n",
+ " # described by lattice vectors X, Y and Z\n",
+ " # The volume is given by the determinant of\n",
+ " # the matrix formed by sticking the three \n",
+ " # vectors together. i.e.\n",
+ " #\n",
+ " # | X[0] Y[0] Z[0] |\n",
+ " # V = | X[1] Y[1] Z[1] |\n",
+ " # | X[2] Y[2] Z[2] |\n",
+ " #\n",
+ " # V = X[0].Y[1].Z[2] + Y[0].Z[1].X[2] \n",
+ " # + X[2].Y[0].Z[1] - Z[0].Y[1].X[2]\n",
+ " # - Y[0].X[1].Z[2] - X[0].Z[1].Y[2]\n",
+ " \n",
+ " assert len(X) == 3, \"X must be a three-vector\"\n",
+ " assert len(Y) == 3, \"Y must be a three-vector\"\n",
+ " assert len(Z) == 3, \"Z must be a three-vector\"\n",
+ " \n",
+ " volume = (X[0]*Y[1]*Z[2] + Y[0]*Z[1]*X[2] + X[2]*Y[0]*Z[1] \n",
+ " - Z[0]*Y[1]*X[2] - Y[0]*X[1]*Z[2] - X[0]*Z[1]*Y[2])\n",
+ " \n",
+ " assert volume >= 0.0, \"The calculated volume must be positive\"\n",
+ " \n",
+ " return volume"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def mean_cell_volume(cell_list):\n",
+ " # Return the avarage volume of a list \n",
+ " # of unit cells. Each element of cell_list\n",
+ " # should be a list of three lattice vectors, \n",
+ " # each with three components. The volume of\n",
+ " # each cell is calculated and summed before \n",
+ " # being devided by the number of cells to give\n",
+ " # the mean volume.\n",
+ " \n",
+ " num_cells = 0\n",
+ " sum_volume = 0.0\n",
+ " for cell in cell_list:\n",
+ " X = cell[0]\n",
+ " Y = cell[1]\n",
+ " Z = cell[2]\n",
+ " sum_volume = sum_volume + cell_volume(X, Y, Z)\n",
+ " num_cells = num_cells + 1\n",
+ " \n",
+ " assert num_cells >= 1, \"One or more cells must be provided\"\n",
+ " mean_volume = sum_volume/num_cells\n",
+ " \n",
+ " return mean_volume"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "AssertionError",
+ "evalue": "Z must be a three-vector",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n\u001b[1;32m 2\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m10.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\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;32m----> 3\u001b[0;31m [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]]])\n\u001b[0m",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mmean_cell_volume\u001b[0;34m(cell_list)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mY\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mZ\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcell\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[0;32m---> 16\u001b[0;31m \u001b[0msum_volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum_volume\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mcell_volume\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mY\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mZ\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mcell_volume\u001b[0;34m(X, Y, Z)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"X must be a three-vector\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mY\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Y must be a three-vector\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mZ\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Z must be a three-vector\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m volume = (X[0]*Y[1]*Z[2] + Y[0]*Z[1]*X[2] + X[2]*Y[0]*Z[1] \n",
+ "\u001b[0;31mAssertionError\u001b[0m: Z must be a three-vector"
+ ]
+ }
+ ],
+ "source": [
+ "mean_cell_volume([[[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]],\n",
+ " [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0]],\n",
+ " [[4.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 6.0]]])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "ZeroDivisionError",
+ "evalue": "float division by zero",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmean_cell_volume\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[0;32m\u001b[0m in \u001b[0;36mmean_cell_volume\u001b[0;34m(cell_list)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnum_cells\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0mmean_volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum_volume\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mnum_cells\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmean_volume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mZeroDivisionError\u001b[0m: float division by zero"
+ ]
+ }
+ ],
+ "source": [
+ "mean_cell_volume([])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "AssertionError",
+ "evalue": "The calculated volume must be positive",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcell_volume\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m10.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6.0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mcell_volume\u001b[0;34m(X, Y, Z)\u001b[0m\n\u001b[1;32m 21\u001b[0m - Z[0]*Y[1]*X[2] - Y[0]*X[1]*Z[2] - X[0]*Z[1]*Y[2])\n\u001b[1;32m 22\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mvolume\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"The calculated volume must be positive\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 24\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mAssertionError\u001b[0m: The calculated volume must be positive"
+ ]
+ }
+ ],
+ "source": [
+ "cell_volume([4.0, 0.0, 0.0], [0.0, -10.0, 0.0], [0.0, 0.0, 6.0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If you are interested - the bug is in cell_volume. This should \n",
+ "return the absolute value of the determinant. The handedness of\n",
+ "the three vectors should not matter."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 2",
+ "language": "python",
+ "name": "python2"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/notes/DefensiveProgrammingNotes.pdf b/notes/DefensiveProgrammingNotes.pdf
new file mode 100644
index 0000000..68a62c1
Binary files /dev/null and b/notes/DefensiveProgrammingNotes.pdf differ
diff --git a/notes/DefensiveProgramming_2_Notes.ipynb b/notes/DefensiveProgramming_2_Notes.ipynb
new file mode 100644
index 0000000..955f6b5
--- /dev/null
+++ b/notes/DefensiveProgramming_2_Notes.ipynb
@@ -0,0 +1,307 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " # Defensive programming (2)\n",
+ " We have seen the basic idea that we can insert\n",
+ " assert statments into code, to check that the \n",
+ " results are what we expect, but how can we test\n",
+ " software more fully? Can doing this help us \n",
+ " avoid bugs in the first place?\n",
+ " \n",
+ " One possible approach is **test driven development**.\n",
+ " Many people think this reduces the number of bugs in \n",
+ " software as it is written, but evidence for this in the \n",
+ " sciences is somewhat limited as it is not always easy \n",
+ " to say what the right answer should be before writing the\n",
+ " software. Having said that, the tests involved in test\n",
+ " driven development are certanly useful even if some of\n",
+ " them are written after the software.\n",
+ " \n",
+ " We will look at a new (and quite difficult) problem, \n",
+ " finding the overlap between ranges of numbers. For \n",
+ " example, these could be the dates that different \n",
+ " sensors were running, and you need to find the \n",
+ " date ranges where all sensors recorded data before\n",
+ " running further analysis."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Start off by imagining you have a working function `range_overlap` that takes\n",
+ "a list of tuples. Write some assert statments that would check if the answer from this\n",
+ "function is correct. Put these in a function. Think of different cases and \n",
+ "about edge cases (which may show a subtle bug)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def test_range_overlap():\n",
+ " assert range_overlap([(-3.0, 5.0), (0.0, 4.5), (-1.5, 2.0)]) == (0.0, 2.0)\n",
+ " assert range_overlap([ (2.0, 3.0), (2.0, 4.0) ]) == (2.0, 3.0)\n",
+ " assert range_overlap([ (0.0, 1.0), (0.0, 2.0), (-1.0, 1.0) ]) == (0.0, 1.0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But what if there is no overlap? What if they just touch?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def test_range_overlap_no_overlap():\n",
+ " assert range_overlap([ (0.0, 1.0), (5.0, 6.0) ]) == None\n",
+ " assert range_overlap([ (0.0, 1.0), (1.0, 2.0) ]) == None"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "What about the case of a single range?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def test_range_overlap_one_range():\n",
+ " assert range_overlap([ (0.0, 1.0) ]) == (0.0, 1.0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The write a solution - one possible one is below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def range_overlap(ranges):\n",
+ " # Return common overlap among a set of [low, high] ranges.\n",
+ " lowest = -1000.0\n",
+ " highest = 1000.0\n",
+ " for (low, high) in ranges:\n",
+ " lowest = max(lowest, low)\n",
+ " highest = min(highest, high)\n",
+ " return (lowest, highest)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And test it..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "test_range_overlap()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "AssertionError",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtest_range_overlap_no_overlap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36mtest_range_overlap_no_overlap\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mtest_range_overlap_no_overlap\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;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mrange_overlap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m5.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6.0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mrange_overlap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2.0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mAssertionError\u001b[0m: "
+ ]
+ }
+ ],
+ "source": [
+ "test_range_overlap_no_overlap()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "test_range_overlap_one_range()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Should we add to the tests?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Can you write version with fewer bugs. My attempt is below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def pairs_overlap(rangeA, rangeB):\n",
+ " # Check if A starts after B ends and \n",
+ " # A ends before B starts. If both are \n",
+ " # false, there is an overlap.\n",
+ " # We are assuming (0.0 1.0) and\n",
+ " # (1.0 2.0) do not overlap. If these should\n",
+ " # overlap swap >= for > and <= for <.\n",
+ " overlap = not ((rangeA[0] >= rangeB[1]) or\n",
+ " (rangeA[1] <= rangeB[0]))\n",
+ " \n",
+ " return overlap\n",
+ "\n",
+ "def find_overlap(rangeA, rangeB):\n",
+ " # Return the overlap between range \n",
+ " # A and B\n",
+ " if pairs_overlap(rangeA, rangeB):\n",
+ " low = max(rangeA[0], rangeB[0])\n",
+ " high = min(rangeA[1], rangeB[1])\n",
+ " return (low, high)\n",
+ " else:\n",
+ " return None\n",
+ "\n",
+ "def range_overlap(ranges):\n",
+ " # Return common overlap among a set of \n",
+ " # [low, high] ranges.\n",
+ "\n",
+ " if len(ranges) == 1:\n",
+ " # Special case of one range - \n",
+ " # overlaps with itself\n",
+ " return(ranges[0])\n",
+ " elif len(ranges) == 2:\n",
+ " # Just return from find_overlap\n",
+ " return find_overlap(ranges[0], ranges[1])\n",
+ " else:\n",
+ " # Range of A, B, C is the \n",
+ " # range of range(B,C) with\n",
+ " # A, etc. Do this by recursion...\n",
+ " overlap = find_overlap(ranges[-1], ranges[-2]) \n",
+ " if overlap is not None:\n",
+ " # Chop off the end of ranges and \n",
+ " # replace with the overlap\n",
+ " ranges = ranges[:-2]\n",
+ " ranges.append(overlap)\n",
+ " # Now run again, with the smaller list.\n",
+ " return range_overlap(ranges)\n",
+ " else:\n",
+ " return None\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "test_range_overlap()\n",
+ "test_range_overlap_one_range()\n",
+ "test_range_overlap_no_overlap()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "It is possible to automate the process of running these tests,\n",
+ "and even plugging the tests into a version control system so \n",
+ "that you know each version passes the tests (or not). We may have\n",
+ "time to look at this tomorrow. But just having the tests isvery \n",
+ "helpful.\n",
+ "\n",
+ "But for now, lets talk about some debugging tips: http://swcarpentry.github.io/python-novice-inflammation/09-debugging.html"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 2",
+ "language": "python",
+ "name": "python2"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/notes/DefensiveProgramming_2_Notes.pdf b/notes/DefensiveProgramming_2_Notes.pdf
new file mode 100644
index 0000000..d5ef77d
Binary files /dev/null and b/notes/DefensiveProgramming_2_Notes.pdf differ
diff --git a/notes/python-overlapping-ranges.svg b/notes/python-overlapping-ranges.svg
new file mode 100644
index 0000000..8f99ac2
--- /dev/null
+++ b/notes/python-overlapping-ranges.svg
@@ -0,0 +1,1418 @@
+
+
\ No newline at end of file
diff --git a/python-overlapping-ranges.svg b/python-overlapping-ranges.svg
new file mode 100644
index 0000000..8f99ac2
--- /dev/null
+++ b/python-overlapping-ranges.svg
@@ -0,0 +1,1418 @@
+
+
\ No newline at end of file