{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "554a1865-998a-41ec-bd1a-f5a5f4630db5",
   "metadata": {},
   "source": [
    "# Bias and variance and extending JIDT code\n",
    "\n",
    "This activity illustrates bias and variance of MI estimates, and gets you started extending the code generated by the JIDT AutoAnalyser.\n",
    "\n",
    "1. Start by generating the code again for the demonstration of the Discrete MI on slides 18/19 of the \"Introduction to JIDT\" lecture slides. Make sure that you have:\n",
    "    * Set the `base` back to 2 for binary data, and\n",
    "    * Set the `time difference` property back to 0 (so we look at the zero lag MI)\n",
    "2. From the generated Python tab from the AutoAnalyer panel (or from the file `demos/AutoAnalyser/GeneratedCalculator.py`) copy and paste the import lines and the lines to start the JVM into the first code cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d3d5c51-29ed-4c2c-9bb7-77abf642b6a7",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Paste the import lines and the lines to start the JVM in this code cell:\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c39e8229-0e66-4f0e-bda0-c34827dea7cf",
   "metadata": {},
   "source": [
    "Paste the remaining code making calculations etc (from the step 0 comments onwards) into the next code cell below.<br/>\n",
    "Splitting the two parts of the code means that we can re-run the code making calculations without having to re-run the code starting the JVM. You can re-run the above code (since it detects and skips starting the JVM if its already running), but it's not necessary. You might want to take this approach whenever you use JIDT in notebooks.<br/>\n",
    "(Alternatively you can just work in a new `.py` file instead of this notebook, which can be placed anywhere).\n",
    "\n",
    "3. Run the two cells to make sure the code still works ok."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cba72e6a-4126-4554-89ae-7d94380a9c24",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Paste the remaining code making calculations etc in this code cell:\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4c7c11e-3d4d-4ac0-b6bf-202b16753e79",
   "metadata": {},
   "source": [
    "4. Edit step 0 of the code which loads the data in to the `source` and `destination` variables:\n",
    "    1. First remove the lines where the file is loaded.\n",
    "    2. Next, change the assignment of the source variable to be an array of 10 random bits: `source = numpy.random.randint(0, 2, 10);` Note that this returns an array of 0's and 1's as required by JIDT.\n",
    "    3. Finally, change the assignment of the destination variable to be a copy of the source: `destination = source;`\n",
    "5. Congratulations, you have made your first extension of the automatically generated JIDT code! Now run the code with these changes.\n",
    "6. Note the result. Was it the full 1 bit of shared information the we would expect for copied random bits?\n",
    "7. Run the code several more times and note the results. Are they always the same or do they vary? Why is this?\n",
    "8. Capture the results of running the code several times (say 10 times) into an array and measure the mean and variance of the results. (_Hint_: in Python you can create an empty array as `results = numpy.zeros(10);`, and then assign into this as say `results[0] = result1;`. You would be best to use a `for` loop to run the code 10 times).\n",
    "    1. Compute the bias as the difference between the mean empirical result and the expected result. It is quite large here because we have computed the empirical results from so few samples (10). In the lecture we noted that MI is typically biased upwards, which referred to situations where variables don't actually share any information; where variables do indeed share information, the MI can be biased downwards as is the case here.\n",
    "    2. Also try to increase the number of samples (e.g. upwards from 10 random bits to 100) and see how the bias and variance change."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "073a3e69-6865-4475-abef-128adf467285",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
