{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "17e37cfc-4332-43e2-9cb7-4c1849ad894e",
   "metadata": {},
   "source": [
    "# Installation check\n",
    "\n",
    "_Copyright (C) 2024-, J.T. Lizier; Distributed under GNU General Public License v3_\n",
    "\n",
    "This is a sample notebook to run to check that your installation works ok\n",
    "\n",
    "**Step 1**: Check standard libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb59c149-9c4e-4d3d-a097-52a72d74244a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipy\n",
    "import matplotlib\n",
    "import pandas\n",
    "import torch\n",
    "# The following should all be built-in already:\n",
    "import random\n",
    "import os\n",
    "import math\n",
    "import string\n",
    "import re\n",
    "\n",
    "print(\"✅ all required packages installed.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69668543-80e6-49ba-8f1c-bf1ac293a2b1",
   "metadata": {},
   "source": [
    "**Step 2**: Check that the platform and python installation are match on 64-bits (else match on 32 bits)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "486906d0-a3cd-4ad2-b207-9d9930116779",
   "metadata": {},
   "outputs": [],
   "source": [
    "import platform\n",
    "import struct\n",
    "\n",
    "# Synthesising suggestions from Copilot and ChatGPT:\n",
    "# a. Machine architecture (OS/CPU)\n",
    "#    Don't use platform.architecture() as this queries the Python executable.\n",
    "machine_arch = platform.machine()\n",
    "#    Now parse this to 32 or 64 bits\n",
    "#    platform.machine() gives strings like 'x86_64', 'AMD64', 'i386', 'arm64', etc.\n",
    "#    May need to update this in future:\n",
    "if \"64\" in machine_arch:\n",
    "    os_arch = 64\n",
    "elif \"86\" in machine_arch or \"32\" in machine_arch:\n",
    "    os_arch = 32\n",
    "else:\n",
    "    os_arch = \"Unknown\"\n",
    "# b. Python interpreter architecture\n",
    "python_arch = struct.calcsize(\"P\") * 8\n",
    "\n",
    "print(f\"Machine: {os_arch}-bit, Python: {python_arch}-bit\")\n",
    "if (os_arch == python_arch):\n",
    "    print(\"✅ Machine and Python architectures match\")\n",
    "else:\n",
    "    print(\"❌ Machine and Python architectures do not match!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e710dca-535c-4d8e-b500-e685f98ecf59",
   "metadata": {},
   "source": [
    "**Step 3**: Check that jpype1 is installed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f276f26f-7829-44ae-8ccb-31ae16ad983d",
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    from jpype import *\n",
    "    print(\"✅ jpype1 is already installed.\")\n",
    "except ImportError:\n",
    "    print(\"❌ jpype1 is not installed!\")\n",
    "    # In principle, we could try to install jpype1 for the user as:\n",
    "    #  !pip install --user jpype1\n",
    "    # However there are too many complications (e.g. pip-v-pip3, externally managed environments, etc).\n",
    "    # So we will ask the user to install jpype1 themselves\n",
    "    print(\"Please use your python package manager (e.g. pip, pip3, homebrew, conda, etc) to install *jpype1* (not jpype).\")\n",
    "    print(\"Then restart the kernel for this notebook, and run the notebook again.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8b30fd4-4502-4b44-8554-5c41ccfb2148",
   "metadata": {},
   "source": [
    "**Step 4**: Check that the `infodynamics.jar` is in the expected location:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33e02580-70e9-4cf6-b355-1b53cc9e944e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Locate the JIDT jar library -- it should be two folders up from the location of this notebook.\n",
    "jarLocation = os.path.join(os.getcwd(), \"..\", \"..\", \"infodynamics.jar\");\n",
    "if (not(os.path.isfile(jarLocation))):\n",
    "    raise Exception(\"infodynamics.jar not found (expected at \" + os.path.abspath(jarLocation))\n",
    "else:\n",
    "    print(\"✅ infodynamics.jar is in the expected location.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9a4f830-be74-45cd-82f3-8de395121ed5",
   "metadata": {},
   "source": [
    "**Step 5**: Check that the Java Virtual Machine (JVM) can be started by the python notebook:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd418112-a0a6-4a39-9626-11f18b33bdd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "if (not isJVMStarted()):\n",
    "    # Add JIDT jar library to the path and\n",
    "    # Start the JVM (add the \"-Xmx\" option with say 1024M if you get crashes due to not enough memory space)\n",
    "    # This should raise an Exception if unsuccessful\n",
    "    startJVM(getDefaultJVMPath(), \"-ea\", \"-Djava.class.path=\" + jarLocation)\n",
    "    if (isJVMStarted()):\n",
    "        print(\"✅ JVM started\")\n",
    "    else:\n",
    "        raise Exception(\"❌ startJVM() ran without exception but the JVM is not started ...?\")\n",
    "else:\n",
    "    print(\"✅ JVM was already started\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3b492f1-12bf-4acf-972a-7cdc62e480c3",
   "metadata": {},
   "source": [
    "**Step 6**: Run a simple calculation with JIDT:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f18beca-d55b-4b8d-8647-256e27787c34",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generate some random binary data for a simple calculation.\n",
    "# Here destArray is a lagged copy of sourceArray:\n",
    "sourceArray = np.random.randint(0, 2, size=100)\n",
    "destArray   = np.empty(100, dtype=int)\n",
    "destArray[0] = 0\n",
    "destArray[1:] = sourceArray[:99]\n",
    "\n",
    "# Create a TE calculator and run it:\n",
    "teCalcClass = JPackage(\"infodynamics.measures.discrete\").TransferEntropyCalculatorDiscrete\n",
    "teCalc = teCalcClass()\n",
    "teCalc.initialise()\n",
    "teCalc.addObservations(sourceArray, destArray)\n",
    "result = teCalc.computeAverageLocalOfObservations()\n",
    "print(\"✅ Calculation ran ok, check that it returned a value close to 1 bit : %.4f bits\" % result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da8ef381-5391-4706-be61-ad931f20d62b",
   "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
}
