{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "ae56fce0",
      "metadata": {},
      "source": [
        "# QDK Interop with OpenQASM"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2b838c23",
      "metadata": {},
      "source": [
        "The QDK provides interoperability with OpenQASM 3 programs built upon the core QDK compiler infrastructure.\n",
        "\n",
        "This core enables integration and local resource estimation without relying on external tools. Users are able to estimate resources for their OpenQASM programs locally (see the [resource estimation with OpenQASM sample notebook](../estimation/estimation-openqasm.ipynb)), leveraging the QDK compiler's capabilities for analysis, transformation, code generation, and simulation. This also enables the generation of QIR from OpenQASM progams leveraging the [QDKs advanced code generation capabilities](https://devblogs.microsoft.com/qsharp/integrated-hybrid-support-in-the-azure-quantum-development-kit/).\n",
        "\n",
        "This includes support for classical instructions available in OpenQASM such as for loops, if statements, switch statements, while loops, binary expresssions, and more.\n",
        "\n",
        "### Simulating OpenQASM programs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "016b3815",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.openqasm import run\n",
        "\n",
        "source = \"\"\"\n",
        "    include \"stdgates.inc\";\n",
        "    bit[2] c;\n",
        "    qubit[2] q;\n",
        "    h q[0];\n",
        "    cx q[0], q[1];\n",
        "    c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "# We'll pass as_bitstring=True to convert bit[n] to a bitstring in the output.\n",
        "# Otherwise, the output would be a list of Result values.\n",
        "run(source, as_bitstring=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "04429707",
      "metadata": {},
      "source": [
        "The OpenQASM programs can also be run with noise just as with Q#."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dc017684",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp import DepolarizingNoise\n",
        "from qsharp.openqasm import run\n",
        "from qsharp_widgets import Histogram\n",
        "\n",
        "source = \"\"\"\n",
        "    include \"stdgates.inc\";\n",
        "    bit[2] c;\n",
        "    qubit[2] q;\n",
        "    h q[0];\n",
        "    cx q[0], q[1];\n",
        "    c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "Histogram(run(source, noise=DepolarizingNoise(0.01), as_bitstring=True))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "981d489a",
      "metadata": {},
      "source": [
        "### Compiling OpenQASM to Quantum Intermediate Representation (QIR)\n",
        "\n",
        "We can directly compile OpenQASM to QIR with the `compile` function."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fc71f209",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.openqasm import compile\n",
        "\n",
        "source = \"\"\"\n",
        "    include \"stdgates.inc\";\n",
        "    bit[2] c;\n",
        "    qubit[2] q;\n",
        "    h q[0];\n",
        "    cx q[0], q[1];\n",
        "    c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "compilation = compile(source)\n",
        "\n",
        "print(compilation)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "95d82f22",
      "metadata": {},
      "source": [
        "> For parameterized circuits the `import_openqasm` function must be used to first create a Python callable. A sample parameterized circuit can be found later in this notebook.\n",
        "\n",
        "### Run OpenQASM 3 Code in interactive session\n",
        "\n",
        "Import the `qsharp` module.\n",
        "\n",
        "This initializes a QDK interpreter singleton."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "75b8b81b",
      "metadata": {},
      "outputs": [],
      "source": [
        "import qsharp\n",
        "qsharp.init(target_profile=qsharp.TargetProfile.Base)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5dc25416",
      "metadata": {},
      "source": [
        "With the runtime initialized, we can import an OpenQASM program as a Python callable. Here we'll compile the OpenQASM program to a callable name `\"bell\"`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "012cc902",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.openqasm import import_openqasm\n",
        "\n",
        "source = \"\"\"\n",
        "    include \"stdgates.inc\";\n",
        "    bit[2] c;\n",
        "    qubit[2] q;\n",
        "    h q[0];\n",
        "    cx q[0], q[1];\n",
        "    c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "import_openqasm(source, name=\"bell\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b95a0c8b",
      "metadata": {},
      "source": [
        "We can now import it via the QDK's Python bindings and run it:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "db043bda",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.code import bell\n",
        "bell()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8db074dc",
      "metadata": {},
      "source": [
        "Additionally, since it is defined in the runtime, we can run it directly from a Q# cell:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ad6d0331",
      "metadata": {
        "vscode": {
          "languageId": "qsharp"
        }
      },
      "outputs": [],
      "source": [
        "%%qsharp\n",
        "bell()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6578cadc",
      "metadata": {},
      "source": [
        "This also unlocks all of the other `qsharp` package functionality. Like noisy simulation. Here we'll use the `run` function showing how we can call into the program from Python and display a histogram:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5bbd6d92",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp import DepolarizingNoise\n",
        "from qsharp.openqasm import run\n",
        "from qsharp.code import bell\n",
        "from qsharp_widgets import Histogram\n",
        "\n",
        "Histogram(run(bell, shots=1000, noise=DepolarizingNoise(0.01)))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "85d48772",
      "metadata": {},
      "source": [
        "We can draw the progam as a textual circuit rendering passing the Python callable into the circuit function:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a0a50634",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.code import bell\n",
        "\n",
        "qsharp.circuit(bell)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5865ea0c",
      "metadata": {},
      "source": [
        "In notebooks, we can do a bit better leveraging the circuit widget:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c3fc87ae",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.code import bell\n",
        "from qsharp_widgets import Circuit\n",
        "\n",
        "Circuit(qsharp.circuit(bell))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0e1a29c8",
      "metadata": {},
      "source": [
        "And finally when getting ready to submit to hardware, we can compile the program to QIR:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ec6db1e5",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.code import bell\n",
        "\n",
        "print(qsharp.compile(bell))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "759f6a5e",
      "metadata": {},
      "source": [
        "We can also define input for the compiled OpenQASM code so that we can parameterize input with imported callables:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bd179f1a",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp import init, TargetProfile\n",
        "from qsharp.openqasm import import_openqasm\n",
        "\n",
        "source = \"\"\"\n",
        "include \"stdgates.inc\";\n",
        "input float theta;\n",
        "bit[2] c;\n",
        "qubit[2] q;\n",
        "rx(theta) q[0];\n",
        "rx(-theta) q[1];\n",
        "c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "init(target_profile=TargetProfile.Base)\n",
        "import_openqasm(source, name=\"parameterized_program\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5b7a97d2",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qsharp.code import parameterized_program\n",
        "from qsharp.openqasm import compile\n",
        "\n",
        "print(compile(parameterized_program, 1.57))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "31d20b6c",
      "metadata": {},
      "source": [
        "When running an OpenQASM program in simulation with qubit loss, additional `Result.Loss` values may be returned that indicate the measured qubit was lost during execution:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "168c3226",
      "metadata": {},
      "outputs": [],
      "source": [
        "init()\n",
        "\n",
        "source = \"\"\"\n",
        "include \"stdgates.inc\";\n",
        "bit[2] c;\n",
        "qubit[2] q;\n",
        "c = measure q;\n",
        "\"\"\"\n",
        "\n",
        "import_openqasm(source, name=\"measure2\")\n",
        "\n",
        "from qsharp.code import measure2\n",
        "\n",
        "Histogram(run(measure2, shots=1000, qubit_loss=0.1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4773ac0e",
      "metadata": {},
      "source": [
        "By using the special include `\"qdk.inc\"` you can check for loss at runtime using the `mresetz_checked` function. It returns an integer with two bits to indicate whether or not loss has occurred, such that `0` or `1` correspond to the qubit measurement and `2` corresponds to loss:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "02a97625",
      "metadata": {},
      "outputs": [],
      "source": [
        "source = \"\"\"\n",
        "include \"stdgates.inc\";\n",
        "include \"qdk.inc\";\n",
        "qubit q;\n",
        "output int res;\n",
        "h q;\n",
        "res = mresetz_checked(q);\n",
        "\"\"\"\n",
        "\n",
        "import_openqasm(source, name=\"mresetz_checked_example\")\n",
        "\n",
        "from qsharp.code import mresetz_checked_example\n",
        "\n",
        "Histogram(run(mresetz_checked_example, shots=1000, qubit_loss=0.1))\n"
      ]
    }
  ],
  "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.13"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
