diff --git a/tutorials/Classiq_tutorial/Qmod_tutorial_part1.ipynb b/tutorials/Classiq_tutorial/Qmod_tutorial_part1.ipynb index b0347d25..b1d5c28e 100644 --- a/tutorials/Classiq_tutorial/Qmod_tutorial_part1.ipynb +++ b/tutorials/Classiq_tutorial/Qmod_tutorial_part1.ipynb @@ -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:" ] @@ -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)" @@ -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", @@ -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", diff --git a/tutorials/Classiq_tutorial/synthesis_tutorial.ipynb b/tutorials/Classiq_tutorial/synthesis_tutorial.ipynb index 7d10c186..a21afb4d 100644 --- a/tutorials/Classiq_tutorial/synthesis_tutorial.ipynb +++ b/tutorials/Classiq_tutorial/synthesis_tutorial.ipynb @@ -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", @@ -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", @@ -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",