From 030bcc4f6b65c91d793cb41ef4ef299784bbf2dd Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 13 Dec 2024 15:20:22 -0800 Subject: [PATCH 1/6] Add Python interop sample notebook This adds a Jupyter notebook sample for invoking Q# callables from Python. I confirmed the new notebook runs in integration tests as expected. --- samples/python_interop/calling_qsharp.ipynb | 356 ++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 samples/python_interop/calling_qsharp.ipynb diff --git a/samples/python_interop/calling_qsharp.ipynb b/samples/python_interop/calling_qsharp.ipynb new file mode 100644 index 0000000000..9090805239 --- /dev/null +++ b/samples/python_interop/calling_qsharp.ipynb @@ -0,0 +1,356 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Invoking Q# callables from Python\n", + "\n", + "The qsharp Python package makes it easy to call Q# operations and functions from within Python. Each Q# callable defined in `%%qsharp` magic cells, through calls to `qsharp.eval()`, or defined in a Q# project loaded via `qsharp.init()` is automatically added to the qsharp.code module in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n let rules = [\n {\n token: \"comment\",\n regex: /(\\/\\/).*/,\n beginWord: false,\n },\n {\n token: \"string\",\n regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n beginWord: false,\n },\n {\n token: \"keyword\",\n regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n beginWord: true,\n },\n {\n token: \"operatorKeyword\",\n regex: String.raw`(not|and|or)\\b|(w/)`,\n beginWord: true,\n },\n {\n token: \"operatorKeyword\",\n regex: String.raw`(=)|(!)|(<)|(>)|(\\+)|(-)|(\\*)|(/)|(\\^)|(%)|(\\|)|(&&&)|(~~~)|(\\.\\.\\.)|(\\.\\.)|(\\?)`,\n beginWord: false,\n },\n {\n token: \"meta\",\n regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n beginWord: true,\n },\n {\n token: \"atom\",\n regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n beginWord: true,\n },\n ];\n let simpleRules = [];\n for (let rule of rules) {\n simpleRules.push({\n token: rule.token,\n regex: new RegExp(rule.regex, \"g\"),\n sol: rule.beginWord,\n });\n if (rule.beginWord) {\n // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n simpleRules.push({\n token: rule.token,\n regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n sol: false,\n });\n }\n }\n\n // Register the mode defined above with CodeMirror\n window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n reg: [/^%%qsharp/],\n };\n\n // Force re-highlighting of all cells the first time this code runs\n for (const cell of window.Jupyter.notebook.get_cells()) {\n cell.auto_highlight();\n }\n });\n}\n", + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import qsharp" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "vscode": { + "languageId": "qsharp" + } + }, + "outputs": [], + "source": [ + "%%qsharp\n", + "\n", + "import Std.Diagnostics.Fact;\n", + "operation TestBellPair() : Result[] {\n", + " use qs = Qubit[2];\n", + " H(qs[0]);\n", + " CNOT(qs[0], qs[1]);\n", + " let rs = MResetEachZ(qs);\n", + " Fact(rs[0] == rs[1], \"The qubits should be in the same state\");\n", + " rs\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Zero, Zero]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qsharp.code.TestBellPair()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Invoking these functions runs the corresponding Q# code against the sparse state simulator and returns the results as Python types, just as if they were invoked with a call to `qsharp.eval()`. They can also be imported from the module so they can be used like any other Python function:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [One, One], [One, One], [Zero, Zero]]\n" + ] + } + ], + "source": [ + "from qsharp.code import TestBellPair\n", + "\n", + "results = [TestBellPair() for _ in range(100)]\n", + "print(results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Arguments to Q# callables are converted from Python 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": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "TypeError: 'float' object cannot be interpreted as an integer\n" + ] + } + ], + "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", + "metadata": {}, + "source": [ + "If you define a Q# callables a namespace (or when loading from a Q# project), they will be exposed with a matching hiearchy of modules in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "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": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "
Basis State
(|𝜓₁…𝜓ₙ⟩)
AmplitudeMeasurement ProbabilityPhase
\n", + " |00⟩\n", + " \n", + " 0.5000+0.0000𝑖\n", + " \n", + " \n", + " 25.0000%\n", + " \n", + " 0.0000\n", + "
\n", + " |01⟩\n", + " \n", + " 0.5000+0.0000𝑖\n", + " \n", + " \n", + " 25.0000%\n", + " \n", + " 0.0000\n", + "
\n", + " |10⟩\n", + " \n", + " 0.5000+0.0000𝑖\n", + " \n", + " \n", + " 25.0000%\n", + " \n", + " 0.0000\n", + "
\n", + " |11⟩\n", + " \n", + " 0.5000+0.0000𝑖\n", + " \n", + " \n", + " 25.0000%\n", + " \n", + " 0.0000\n", + "
\n", + "\n", + "\n", + "$|\\psi\\rangle = \\frac{1}{2}|00\\rangle+\\frac{1}{2}|01\\rangle+\\frac{1}{2}|10\\rangle+\\frac{1}{2}|11\\rangle$" + ], + "text/plain": [ + "STATE:\n", + "|00⟩: 0.5000+0.0000𝑖\n", + "|01⟩: 0.5000+0.0000𝑖\n", + "|10⟩: 0.5000+0.0000𝑖\n", + "|11⟩: 0.5000+0.0000𝑖" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qsharp.code.Foo import Bar\n", + "\n", + "Bar()" + ] + }, + { + "cell_type": "markdown", + "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": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "QsharpError: callable not found\n" + ] + } + ], + "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": 2 +} From 49d04523fe44545595df825a2b89f22fd2264020 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 15 Dec 2024 15:21:32 -0800 Subject: [PATCH 2/6] Update some existing samples --- samples/notebooks/project.ipynb | 25 +++++++++++++++++++++++-- samples/notebooks/sample.ipynb | 26 ++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/samples/notebooks/project.ipynb b/samples/notebooks/project.ipynb index 5dc634ed0d..0c3da1c4bf 100644 --- a/samples/notebooks/project.ipynb +++ b/samples/notebooks/project.ipynb @@ -42,11 +42,32 @@ "\n", "Sample.Main()\n" ] + }, + { + "cell_type": "markdown", + "id": "5fad86c4", + "metadata": {}, + "source": [ + "The callables from the project are also available under `qsharp.code` and can be called or imported from Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "423b6fc4", + "metadata": {}, + "outputs": [], + "source": [ + "from qsharp.code.Sample import Main\n", + "\n", + "res = Main()\n", + "print(f\"Got return value from Q# code: {res}\")" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -60,7 +81,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.11" } }, "nbformat": 4, diff --git a/samples/notebooks/sample.ipynb b/samples/notebooks/sample.ipynb index 583a999a25..42a9dbf7bc 100644 --- a/samples/notebooks/sample.ipynb +++ b/samples/notebooks/sample.ipynb @@ -69,7 +69,7 @@ "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" + "`DumpMachine()` and `Message()` print to stdout and get displayed in the notebook as plain text." ] }, { @@ -84,6 +84,24 @@ "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", @@ -256,7 +274,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "eb3cd29f", "metadata": { "vscode": { @@ -382,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "9b85eb2d", "metadata": { "vscode": { @@ -432,7 +450,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.1" + "version": "3.11.11" } }, "nbformat": 4, From d6d11df85248933caeb6339df00558d87d9fba52 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Sun, 15 Dec 2024 15:30:49 -0800 Subject: [PATCH 3/6] Consolidate into sample.ipynb --- samples/notebooks/sample.ipynb | 106 +++++- samples/python_interop/calling_qsharp.ipynb | 356 -------------------- 2 files changed, 100 insertions(+), 362 deletions(-) delete mode 100644 samples/python_interop/calling_qsharp.ipynb diff --git a/samples/notebooks/sample.ipynb b/samples/notebooks/sample.ipynb index 42a9dbf7bc..53effbca45 100644 --- a/samples/notebooks/sample.ipynb +++ b/samples/notebooks/sample.ipynb @@ -10,12 +10,6 @@ "This enables the `%%qsharp` magic and initializes a Q# interpreter singleton." ] }, - { - "cell_type": "markdown", - "id": "ed1b75bf", - "metadata": {}, - "source": [] - }, { "cell_type": "code", "execution_count": null, @@ -432,6 +426,106 @@ "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 a Q# callables a namespace (or when loading from a Q# project), they will be exposed with a matching hiearchy of modules in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "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": { diff --git a/samples/python_interop/calling_qsharp.ipynb b/samples/python_interop/calling_qsharp.ipynb deleted file mode 100644 index 9090805239..0000000000 --- a/samples/python_interop/calling_qsharp.ipynb +++ /dev/null @@ -1,356 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Invoking Q# callables from Python\n", - "\n", - "The qsharp Python package makes it easy to call Q# operations and functions from within Python. Each Q# callable defined in `%%qsharp` magic cells, through calls to `qsharp.eval()`, or defined in a Q# project loaded via `qsharp.init()` is automatically added to the qsharp.code module in Python:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n let rules = [\n {\n token: \"comment\",\n regex: /(\\/\\/).*/,\n beginWord: false,\n },\n {\n token: \"string\",\n regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n beginWord: false,\n },\n {\n token: \"keyword\",\n regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n beginWord: true,\n },\n {\n token: \"keyword\",\n regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n beginWord: true,\n },\n {\n token: \"operatorKeyword\",\n regex: String.raw`(not|and|or)\\b|(w/)`,\n beginWord: true,\n },\n {\n token: \"operatorKeyword\",\n regex: String.raw`(=)|(!)|(<)|(>)|(\\+)|(-)|(\\*)|(/)|(\\^)|(%)|(\\|)|(&&&)|(~~~)|(\\.\\.\\.)|(\\.\\.)|(\\?)`,\n beginWord: false,\n },\n {\n token: \"meta\",\n regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n beginWord: true,\n },\n {\n token: \"atom\",\n regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n beginWord: true,\n },\n ];\n let simpleRules = [];\n for (let rule of rules) {\n simpleRules.push({\n token: rule.token,\n regex: new RegExp(rule.regex, \"g\"),\n sol: rule.beginWord,\n });\n if (rule.beginWord) {\n // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n simpleRules.push({\n token: rule.token,\n regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n sol: false,\n });\n }\n }\n\n // Register the mode defined above with CodeMirror\n window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n reg: [/^%%qsharp/],\n };\n\n // Force re-highlighting of all cells the first time this code runs\n for (const cell of window.Jupyter.notebook.get_cells()) {\n cell.auto_highlight();\n }\n });\n}\n", - "text/plain": [] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import qsharp" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "vscode": { - "languageId": "qsharp" - } - }, - "outputs": [], - "source": [ - "%%qsharp\n", - "\n", - "import Std.Diagnostics.Fact;\n", - "operation TestBellPair() : Result[] {\n", - " use qs = Qubit[2];\n", - " H(qs[0]);\n", - " CNOT(qs[0], qs[1]);\n", - " let rs = MResetEachZ(qs);\n", - " Fact(rs[0] == rs[1], \"The qubits should be in the same state\");\n", - " rs\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Zero, Zero]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "qsharp.code.TestBellPair()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Invoking these functions runs the corresponding Q# code against the sparse state simulator and returns the results as Python types, just as if they were invoked with a call to `qsharp.eval()`. They can also be imported from the module so they can be used like any other Python function:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [Zero, Zero], [Zero, Zero], [Zero, Zero], [One, One], [Zero, Zero], [Zero, Zero], [One, One], [One, One], [Zero, Zero], [One, One], [Zero, Zero], [One, One], [One, One], [One, One], [Zero, Zero]]\n" - ] - } - ], - "source": [ - "from qsharp.code import TestBellPair\n", - "\n", - "results = [TestBellPair() for _ in range(100)]\n", - "print(results)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Arguments to Q# callables are converted from Python 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": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n", - "TypeError: 'float' object cannot be interpreted as an integer\n" - ] - } - ], - "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", - "metadata": {}, - "source": [ - "If you define a Q# callables a namespace (or when loading from a Q# project), they will be exposed with a matching hiearchy of modules in Python:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "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": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - "
Basis State
(|𝜓₁…𝜓ₙ⟩)
AmplitudeMeasurement ProbabilityPhase
\n", - " |00⟩\n", - " \n", - " 0.5000+0.0000𝑖\n", - " \n", - " \n", - " 25.0000%\n", - " \n", - " 0.0000\n", - "
\n", - " |01⟩\n", - " \n", - " 0.5000+0.0000𝑖\n", - " \n", - " \n", - " 25.0000%\n", - " \n", - " 0.0000\n", - "
\n", - " |10⟩\n", - " \n", - " 0.5000+0.0000𝑖\n", - " \n", - " \n", - " 25.0000%\n", - " \n", - " 0.0000\n", - "
\n", - " |11⟩\n", - " \n", - " 0.5000+0.0000𝑖\n", - " \n", - " \n", - " 25.0000%\n", - " \n", - " 0.0000\n", - "
\n", - "\n", - "\n", - "$|\\psi\\rangle = \\frac{1}{2}|00\\rangle+\\frac{1}{2}|01\\rangle+\\frac{1}{2}|10\\rangle+\\frac{1}{2}|11\\rangle$" - ], - "text/plain": [ - "STATE:\n", - "|00⟩: 0.5000+0.0000𝑖\n", - "|01⟩: 0.5000+0.0000𝑖\n", - "|10⟩: 0.5000+0.0000𝑖\n", - "|11⟩: 0.5000+0.0000𝑖" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from qsharp.code.Foo import Bar\n", - "\n", - "Bar()" - ] - }, - { - "cell_type": "markdown", - "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": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "QsharpError: callable not found\n" - ] - } - ], - "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": 2 -} From 875948ceb050d331b86e643ef80ce8bef1c389fb Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Wed, 18 Dec 2024 15:30:04 -0800 Subject: [PATCH 4/6] Update generating_n_random_bits sample --- .../generating_n_random_bits/RunGenerateRandom.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/python_interop/generating_n_random_bits/RunGenerateRandom.py b/samples/python_interop/generating_n_random_bits/RunGenerateRandom.py index cf62304a8f..f1d90a1830 100644 --- a/samples/python_interop/generating_n_random_bits/RunGenerateRandom.py +++ b/samples/python_interop/generating_n_random_bits/RunGenerateRandom.py @@ -2,10 +2,10 @@ qsharp.init(project_root=".") +from qsharp.code.GenerateRandomNumbers import GenerateRandomNumbers + nQubits = input("Enter the number of random bits to be generated: ") -(results, number) = qsharp.eval( - f"GenerateRandomNumbers.GenerateRandomNumbers({nQubits})" -) +(results, number) = GenerateRandomNumbers(int(nQubits)) count = 0 for result in results: From 359b6d70d50fb40b866c4ee70d13467392578d60 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 19 Dec 2024 09:58:52 -0800 Subject: [PATCH 5/6] Fix typos in notebook sample, clear execution numbers from cells --- samples/notebooks/sample.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/notebooks/sample.ipynb b/samples/notebooks/sample.ipynb index 53effbca45..a7899a9cf1 100644 --- a/samples/notebooks/sample.ipynb +++ b/samples/notebooks/sample.ipynb @@ -394,7 +394,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 14, "id": "9b85eb2d", "metadata": { "vscode": { @@ -463,12 +463,12 @@ "id": "0f0795e9", "metadata": {}, "source": [ - "If you define a Q# callables a namespace (or when loading from a Q# project), they will be exposed with a matching hiearchy of modules in Python:" + "If you define any Q# callables 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": 25, + "execution_count": null, "id": "e7b84a41", "metadata": { "vscode": { From 1d4b5c65ce9a9eecdddf769cc5d0dd80d460450e Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Thu, 19 Dec 2024 11:33:30 -0800 Subject: [PATCH 6/6] Fix message again --- samples/notebooks/sample.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/notebooks/sample.ipynb b/samples/notebooks/sample.ipynb index a7899a9cf1..1d60bd2c1e 100644 --- a/samples/notebooks/sample.ipynb +++ b/samples/notebooks/sample.ipynb @@ -463,7 +463,7 @@ "id": "0f0795e9", "metadata": {}, "source": [ - "If you define any Q# callables a namespace (or when initializing with a Q# project), those callables will be exposed with a matching hierarchy of modules in Python:" + "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:" ] }, {