Skip to content

Commit

Permalink
Terminology/wording/code improvements we did in an online session
Browse files Browse the repository at this point in the history
  • Loading branch information
matanvax2 committed Feb 19, 2025
1 parent 42b4e82 commit 74c83fc
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 62 deletions.
29 changes: 15 additions & 14 deletions tutorials/Classiq_tutorial/Qmod_tutorial_part1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In this tutorial, we will cover the basics of the Qmod language and its accompanied function library.\\\n",
"We will learn to use quantum variables, functions and operators.\n",
"In this tutorial, we will cover the basics of the Qmod language and its accompanying library.\\\n",
"We will learn to use quantum variables, functions, and operators.\n",
"\n",
"Let's begin with a simple code example:"
]
Expand All @@ -32,7 +32,7 @@
"\n",
"@qfunc\n",
"def main(q: Output[QBit]) -> None:\n",
" allocate(1,q)\n",
" allocate(q)\n",
" foo(q)\n",
"\n",
"qmod = create_model(main)"
Expand All @@ -42,13 +42,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The function `foo` is defined to get an input variable `q` of type `QBit` and apply on it `X` gate, followed by `H` gate.\\\n",
"The function `main` is defined with a single `Output` variable `q` of type `QBit`. It first allocates a qubit to `q`, than calls `foo` to act on it.\n",
"A Quantum model `qmod` is created based on the function `main`, so that it can later be synthesized and executed.\n",
"Function `foo` takes the quantum parameter `q` of type `QBit` and applies `X` gate to it, followed by `H` gate.\\\n",
"Function `main` declares a single `Output` parameter `q` of type `QBit`. It first allocates a qubit to `q`, then calls `foo` to operate on it.\n",
"A representation of the model `qmod` is created based on function `main`, so that it can later be synthesized and executed.\n",
"\n",
"What results do we expect when executing this model?\n",
"- By calling `allocate`, `q` is initialized in the default state $|0\\rangle$.\n",
"- Then, foo is called:\n",
"- Then, `foo` is called:\n",
" - It applies `X` (NOT gate), changing `q`'s state to $|1\\rangle$.\n",
" - Then it applies `H` (Hadamard gate), resulting in the superposition $\\frac{1}{\\sqrt{2}} (|0\\rangle - |1\\rangle)$.\n",
"\n",
Expand Down Expand Up @@ -81,18 +81,19 @@
"metadata": {},
"source": [
"## Qmod Fundementals\n",
"This simple model demonstrates several features that are essential in every Qmod code:\n",
"The simple model above demonstrates several features that are essential in every Qmod code:\n",
"\n",
"1. The `@qfunc` decorator:\\\n",
" Qmod is a quantum computing language embeded into Python. The decorator `@qfunc` marks a Qmod function, so that the Qmod interpreter is called to handle it. The decorator is used in every quantum function definition.\n",
" Qmod is a quantum programming language embedded in Python. The decorator `@qfunc` designates a quantum function, so that it can be processed by the Qmod tool chain. The Python function is executed at a later point to construct the Qmod representation. This decorator is used for every Qmod function definition.\n",
"\n",
"2. The function `main`:\\\n",
" Any Qmod code that is intended to be synthesized into an executable quantum program must define a function `main`. The function `main` acts as the program's quantum entry point - it specifies the inputs and outputs of the quantum program, that is, its interface with the external classical execution logic. Other functions (`foo` as an example) can of course be defined and called, but if we track back the function calls they always point back to `main`.\n",
"2. Function `main`:\\\n",
" A complete Qmod model, that is, a description that can be synthesized and executed, must define a function called `main`. Function `main` is the quantum entry point - it specifies the inputs and outputs of the quantum program, that is, its interface with the external classical execution logic. Similar to conventional programming languages, function `main`, can call other functions.\n",
"\n",
"3. Quantum variables initialization:\\\n",
"3. Quantum variable initialization:\\\n",
" ## TODO: Dror - variables are initialized to reference some quantum object..\n",
" Every quantum variable must be initialized. Initialization means __allocating qubits to the variable and determining its initial state__. There are several ways to initialize a quantum variable:\n",
" - The most basic way demonstrated above is calling `allocate`. This method requires specifying directly the number of qubits to be allocated to the variable, and the state of all these qubits is automatically set to the default $|0\\rangle$. \n",
" - More advanced methods (to be covered later) include assigning an arithmetic expresssion to the variable, calling state-preparation function and more - such methods automatically determine the number of qubits to allocate based on the information that we wish the variable to represent.\n",
" - The simplest way (demonstrated above) is using `allocate`. It can optionally specify the number of qubits to be allocated to the variable. The state of all these qubits is automatically set to the default $|0\\rangle$. \n",
" - More methods (to be covered later) include assigning an arithmetic expression to the variable, or passing it as argument to an output parameter of a function - such methods automatically determine the number of qubits to allocate based on the information that we wish the variable to represent.\n",
" \n",
"4. The `Output` modifier:\\\n",
" The `Output` modifier indicates that a quantum variable is not initialized outside the scope of the function, and hence must be initialized inside the scope of the function.\\\n",
Expand Down
110 changes: 62 additions & 48 deletions tutorials/Classiq_tutorial/synthesis_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,71 +6,80 @@
"source": [
"# Synthesis Tutorial\n",
"\n",
"Classiq synthesis engine takes a high-level program written in Classiq's Qmod language, and compiles it into an executable gate-based circuit.\\\n",
"In most cases, there is not a single implementation that is superior in all manners - there might be one implementation that requires the lowest number of qubits, another that minimizes the gate-count etc. \n",
"Classiq's synthesis engine takes a high-level model written in the Qmod language, and compiles it into an executable gate-level circuit.\\\n",
"When mapping high-level functionality to concrete circuits, there may be many different but equivalent possible implementations that reflect tradeoffs in the overall depth, width, gate counts, etc. For example, implementing a multi-controlled-not operation can be shallower in gates given more auxiliary qubits. Choosing the best implementation for a specific operation instance depends on the overall constraints and objectives, as well as the specific structure of the quantum program.\n",
"\n",
"Let's look at a simple model, and use Classiq synthesis engine to compile it according to different optimization parameters."
"Let's look at a simple model, and use Classiq's synthesis engine to compile it given different optimization objectives."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"metadata": {
"ExecuteTime": {
"end_time": "2025-02-19T09:57:25.784056Z",
"start_time": "2025-02-19T09:57:25.755663Z"
}
},
"source": [
"from classiq import *\n",
"\n",
"@qfunc\n",
"def main(x: Output[QNum], y: Output[QNum]) -> None:\n",
" allocate(3,x)\n",
"def main(x: Output[QNum[3]], y: Output[QNum]) -> None:\n",
" allocate(x)\n",
" hadamard_transform(x)\n",
" y |= x**2 + 1"
]
],
"outputs": [],
"execution_count": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, let's synthesize to optimize circuit depth, i.e. to minimize longest chain of gates in the circuit."
]
"source": "First, let's synthesize to optimize on circuit depth, i.e. to minimize the longest chain of gates in the circuit and hence the overall execution time (and required coherence time)."
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"metadata": {
"ExecuteTime": {
"end_time": "2025-02-19T09:57:33.595260Z",
"start_time": "2025-02-19T09:57:25.795982Z"
}
},
"source": [
"qmod_opt_depth = create_model(\n",
" entry_point=main,\n",
"qprog_opt_depth = synthesize(\n",
" model=main,\n",
" constraints=Constraints(optimization_parameter=OptimizationParameter.DEPTH) \n",
")\n",
"\n",
"qprog_opt_depth = synthesize(qmod_opt_depth)"
]
")"
],
"outputs": [],
"execution_count": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can inspect the resulting curcuit using Classiq's web visualization:\n"
]
"source": "We can inspect the resulting circuit using Classiq's web visualization:\n"
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2025-02-19T09:57:35.150980Z",
"start_time": "2025-02-19T09:57:33.606889Z"
}
},
"source": [
"show(qprog_opt_depth)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Opening: https://platform.classiq.io/circuit/2t7ALaL8G99fehfqWPbX4pjBim5?version=0.68.0\n"
"Opening: https://platform.classiq.io/circuit/2tFsFhhCaOu0oxISGTKjXSkbSty?version=0.68.0\n"
]
}
],
"source": [
"show(qprog_opt_depth)"
]
"execution_count": 5
},
{
"cell_type": "markdown",
Expand All @@ -94,23 +103,25 @@
"source": [
"The resulting depth and width are 42 and 16, respectively.\n",
"\n",
"Now, let's synthesize to optimize width, i.e to minimize the number of qubits used.\\\n",
"We can do it by calling `set_constraints`, which overrides the current `constraints` parameter:"
"Now, let's synthesize to optimize width, i.e to minimize the number of qubits used.\\"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"metadata": {
"ExecuteTime": {
"end_time": "2025-02-19T09:57:38.617264Z",
"start_time": "2025-02-19T09:57:35.204530Z"
}
},
"source": [
"qmod_opt_width = set_constraints(\n",
" serialized_model=qmod_opt_depth,\n",
" constraints=Constraints(optimization_parameter=OptimizationParameter.WIDTH)\n",
")\n",
"\n",
"qprog_opt_widht = synthesize(qmod_opt_width)"
]
"qprog_opt_width = synthesize(\n",
" model=main,\n",
" constraints=Constraints(optimization_parameter=OptimizationParameter.WIDTH) \n",
")"
],
"outputs": [],
"execution_count": 6
},
{
"cell_type": "markdown",
Expand All @@ -121,20 +132,23 @@
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2025-02-19T09:57:39.812986Z",
"start_time": "2025-02-19T09:57:38.625126Z"
}
},
"source": "show(qprog_opt_width)",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Opening: https://platform.classiq.io/circuit/2t7AMF1Pqypoa1FfklsGHOz6E2Z?version=0.68.0\n"
"Opening: https://platform.classiq.io/circuit/2tFsGKc7EHcx0fX3oXREB18FTjd?version=0.68.0\n"
]
}
],
"source": [
"show(qprog_opt_widht)"
]
"execution_count": 7
},
{
"cell_type": "markdown",
Expand Down

0 comments on commit 74c83fc

Please sign in to comment.