Skip to content

Commit

Permalink
Add Python interop sample notebook (#2066)
Browse files Browse the repository at this point in the history
This adds a Jupyter notebook sample for invoking Q# callables from
Python. I confirmed the new notebook runs in integration tests as
expected.
  • Loading branch information
swernli authored Dec 20, 2024
1 parent 0e3c2d7 commit 939e2aa
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 15 deletions.
25 changes: 23 additions & 2 deletions samples/notebooks/project.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand All @@ -60,7 +81,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
"version": "3.11.11"
}
},
"nbformat": 4,
Expand Down
132 changes: 122 additions & 10 deletions samples/notebooks/sample.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -69,7 +63,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."
]
},
{
Expand All @@ -84,6 +78,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",
Expand Down Expand Up @@ -256,7 +268,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"id": "eb3cd29f",
"metadata": {
"vscode": {
Expand Down Expand Up @@ -382,7 +394,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 14,
"id": "9b85eb2d",
"metadata": {
"vscode": {
Expand Down Expand Up @@ -414,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 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": {
Expand All @@ -432,7 +544,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.1"
"version": "3.11.11"
}
},
"nbformat": 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 939e2aa

Please sign in to comment.