{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a2f48f2b",
   "metadata": {},
   "source": [
    "Import the Q# module.\n",
    "\n",
    "This enables the `%%qsharp` magic and initializes a Q# interpreter singleton."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e8e4faa",
   "metadata": {},
   "outputs": [],
   "source": [
    "import qsharp\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a536d53",
   "metadata": {},
   "source": [
    "Run Q# using the `%%qsharp` magic.\n",
    "\n",
    "`DumpMachine()` and `Message()` output get formatted as HTML. Return value is shown as cell output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9df62352",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation Main() : Result {\n",
    "    use q = Qubit();\n",
    "    X(q);\n",
    "    Std.Diagnostics.DumpMachine();\n",
    "    let r = M(q);\n",
    "    Message($\"The result of the measurement is {r}\");\n",
    "    Reset(q);\n",
    "    r\n",
    "}\n",
    "\n",
    "Main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4584c494",
   "metadata": {},
   "source": [
    "`qsharp.eval()` does the same thing as the `%%qsharp` magic.\n",
    "\n",
    "`DumpMachine()` and `Message()` print to stdout and get displayed in the notebook as plain text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d0995bf",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "qsharp.eval(\"Main()\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19f4ef6d",
   "metadata": {},
   "source": [
    "`qsharp.code` provides direct access to simulating callables defined in Q#."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30b92222",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.code.Main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3bde193",
   "metadata": {},
   "source": [
    "Assign a result to a Python variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50383f8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "result = qsharp.eval(\"1 + 2\")\n",
    "\n",
    "print(f\"Result: {result} (type: {type(result).__name__})\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b06b7857",
   "metadata": {},
   "source": [
    "Errors are exceptions. \n",
    "\n",
    "Catch and handle compilation errors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33fd3c4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qsharp import QSharpError\n",
    "\n",
    "try:\n",
    "    qsharp.eval(\n",
    "        \"\"\"\n",
    "operation Foo() : Unit {\n",
    "    Bar();\n",
    "    Baz();\n",
    "}\n",
    "\"\"\"\n",
    "    )\n",
    "except QSharpError as ex:\n",
    "    print(ex)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00f82a16",
   "metadata": {},
   "source": [
    "Catch and handle runtime errors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e70a95d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    qsharp.eval(\"operation Foo() : Unit { use q = Qubit(); X(q) } Foo()\")\n",
    "except QSharpError as ex:\n",
    "    print(ex)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e294471",
   "metadata": {},
   "source": [
    "A runtime error that's not caught gets reported as a Python exception."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d40d86cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.eval(\"operation Foo() : Unit { use q = Qubit(); X(q) } Foo()\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba2f98ad",
   "metadata": {},
   "source": [
    "In `%%qsharp` cells, exceptions are handled and displayed as error text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b55e53c",
   "metadata": {
    "scrolled": false,
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation Bar() : Unit {\n",
    "    use q = Qubit();\n",
    "    Std.Diagnostics.DumpMachine();\n",
    "    X(q);\n",
    "}\n",
    "\n",
    "Bar()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98247ac2",
   "metadata": {},
   "source": [
    "Streaming output for long running operations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bd25ae87",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "import Std.Diagnostics.*;\n",
    "\n",
    "operation Main() : Unit {\n",
    "    Message(\"Generating random bit... \");\n",
    "    for i in 0..400000 {\n",
    "        use q = Qubit();\n",
    "        H(q);\n",
    "        let r = M(q);\n",
    "        if (i % 100000) == 0 {\n",
    "            DumpMachine();\n",
    "            Message($\"Result: {r}\");\n",
    "        }\n",
    "        Reset(q);\n",
    "    }\n",
    "}\n",
    "\n",
    "Main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a2d9e7d",
   "metadata": {},
   "source": [
    "Running multiple shots for an expression. Each shot uses an independent instance of the simulator. A list of results (or runtime errors) is returned."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "eb3cd29f",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation RandomBit() : Result {\n",
    "    use q = Qubit();\n",
    "    H(q);\n",
    "    let res = M(q);\n",
    "    Reset(q);\n",
    "    return res;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a9f5335",
   "metadata": {},
   "outputs": [],
   "source": [
    "results = qsharp.run(\"RandomBit()\", 10)\n",
    "\n",
    "results\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a476e6d",
   "metadata": {},
   "source": [
    "The results can then be processed, e.g. plotted in a histogram using popular Python libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7bd77379",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install matplotlib\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "83cee4e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from collections import Counter\n",
    "\n",
    "# Sort the results so that the histogram labels appear in the correct order\n",
    "results.sort()\n",
    "# Count the number of times each result appears\n",
    "counts = Counter(results)\n",
    "\n",
    "(values, counts) = counts.keys(), counts.values()\n",
    "xlabels = np.arange(len(counts))\n",
    "plt.bar(xlabels, counts)\n",
    "plt.xticks(xlabels, values)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eaf766f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install pandas\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8095640a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas\n",
    "from collections import Counter\n",
    "\n",
    "# Sort the results so that the histogram labels appear in the correct order\n",
    "results.sort()\n",
    "pandas.Series(results).value_counts(sort=False).plot(kind='bar')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "990642e4",
   "metadata": {},
   "source": [
    "A compiler error in the entry expression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f045ad9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.run(\"\"\"RandomBit(\"a\")\"\"\", 10)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ba56462",
   "metadata": {},
   "source": [
    "Some shots throw runtime errors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9b85eb2d",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "operation Bad() : Unit {\n",
    "    use q = Qubit();\n",
    "    H(q);\n",
    "    let res = M(q);\n",
    "    if (res == One) {\n",
    "        // Do something bad, sometimes\n",
    "        use q2 = Qubit();\n",
    "        X(q2);\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2445df05",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.run(\"Bad()\", 10)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f738245",
   "metadata": {},
   "source": [
    "When invoked from Python, arguments to Q# callables are converted from their Python type to the expected Q# type. If an argument cannot be converted to the right type, it will trigger a runtime exception."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ae2729d",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.eval(\"\"\"\n",
    "    function AddTwoInts(a : Int, b : Int) : Int {\n",
    "        return a + b;\n",
    "    }\n",
    "    \"\"\")\n",
    "\n",
    "from qsharp.code import AddTwoInts\n",
    "\n",
    "print(AddTwoInts(2, 3))\n",
    "\n",
    "try:\n",
    "    AddTwoInts(2, 3.0)\n",
    "except TypeError as e:\n",
    "    print(f\"TypeError: {e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f0795e9",
   "metadata": {},
   "source": [
    "If you define any Q# callables in a namespace (or when initializing with a Q# project), those callables will be exposed with a matching hierarchy of modules in Python:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7b84a41",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "import Std.Diagnostics.DumpMachine;\n",
    "namespace Foo {\n",
    "    operation Bar() : Unit {\n",
    "        use qs = Qubit[2];\n",
    "        for q in qs {\n",
    "            H(q);\n",
    "        }\n",
    "        DumpMachine();\n",
    "        ResetAll(qs);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5591587c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qsharp.code.Foo import Bar\n",
    "\n",
    "Bar()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "020b244b",
   "metadata": {},
   "source": [
    "If you run `qsharp.init()`, the compiler and simulator state are reset and all functions exposed into Python are cleared:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d73c247",
   "metadata": {},
   "outputs": [],
   "source": [
    "qsharp.init()\n",
    "\n",
    "try:\n",
    "    Bar()\n",
    "except qsharp.QSharpError as e:\n",
    "    print(f\"QsharpError: {e}\")"
   ]
  }
 ],
 "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.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
