Skip to content

Commit

Permalink
English suggestions to Introducing Quantum Functions with Quantum Mon…
Browse files Browse the repository at this point in the history
…te Carlo Integration
  • Loading branch information
AnnePicus authored and ravidalon committed Dec 25, 2024
1 parent 36d4119 commit a0fa141
Showing 1 changed file with 51 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"id": "456a591a-6383-45cf-ac3e-cca3014edf6b",
"metadata": {},
"source": [
"# Introducing quantum functions with Quantum Monte Carlo Integration\n",
"# Introducing Quantum Functions with Quantum Monte Carlo Integration\n",
"\n",
"In this tutorial we introduce how to write custom quantum functions with Classiq, and subsequently use them for more complex functions/algorithms. This will be illustrated on a specific use-case of Quantum Monte Carlo Integration (QMCI). The example below demonstrates how we can exploit various concepts of modeling quantum algorithms with Classiq when building our own functions."
"This tutorial explains how to write custom quantum functions with Classiq and subsequently uses them for more complex functions or algorithms. This is illustrated on a specific use case of Quantum Monte Carlo Integration (QMCI). The example below demonstrates how we can exploit various concepts of modeling quantum algorithms with Classiq when building our own functions."
]
},
{
Expand All @@ -25,26 +25,26 @@
"\\tag{1}\n",
"E_{p}(x) = \\int f(x)p(x) dx.\n",
"\\end{equation}\n",
"Such evaluations appear in the context of option-pricing or credit risk-analysis.\n",
"Such evaluations appear in the context of option pricing or credit risk analysis.\n",
"\n",
"The basic idea of QMCI assumes that we have a quantum function $A$, which, for a given $f$ and $p$, loads the following state of $n+1$ qubits:\n",
"\\begin{align}\n",
"\\tag{2}\n",
"A|0\\rangle_n|0\\rangle = \\sum^{2^n-1}_{i=0} \\sqrt{f_i} \\sqrt{p_i}|i\\rangle_n|1\\rangle + \\sum^{2^n-1}_{i=0} \\sqrt{1-f_i} \\sqrt{p_i}|i\\rangle_n|0\\rangle = \\sqrt{a}|\\psi_1\\rangle+\\sqrt{1-a^2}|\\psi_0\\rangle,\n",
"\\end{align}\n",
"where it is understood that the first $2^n$ states represent a discretized space of $x$, and that $0\\leq f(x)\\leq 1$.\n",
"Then, by applying Amplitude Estimation (AE) algorithm for the \"good-state\" $|\\psi_1 \\rangle$, we can estimate its amplitude\n",
"Then, by applying the amplitude estimation (AE) algorithm for the \"good-state\" $|\\psi_1 \\rangle$, we can estimate its amplitude:\n",
"$$\n",
"a = \\sum^{2^n-1}_{i=0} f_i p_i.\n",
"$$\n",
"\n",
"The QMCI algorithm can be separated into two parts:\n",
"1) Constructing a Grover operator for the specific problem--- this will be done here almost from scratch.\n",
"2) Applying AE algorithm based on the Grover operator [[1](#AE)]--- this will be done by calling Classiq's Quantum Phase Estimation (QPE) function.\n",
"1) Constructing a Grover operator for the specific problem. This is done here almost from scratch.\n",
"2) Applying the AE algorithm based on the Grover operator [[1](#AE)]. This is done by calling the Classiq Quantum Phase Estimation (QPE) function.\n",
"\n",
"### Specific use-case for the tutorial\n",
"### Specific Use Case for the Tutorial\n",
"\n",
"For simplicity we will consider a simple use-case. We take a probability distribution on the integers\n",
"For simplicity we consider a simple use case. We take a probability distribution on the integers\n",
"$$\n",
"\\tag{3}\n",
"p_i = \\frac{i}{\\mathcal{N}} \\text{ for } i\\in \\{0,\\dots 2^3-1\\},\n",
Expand All @@ -54,7 +54,7 @@
"\\tag{4}\n",
"f(x) = \\sin^2(0.25x+0.2).\n",
"$$\n",
"Therefore, the value we want to evaluate is:\n",
"Therefore, the value we want to evaluate is\n",
"$$\n",
"a= \\frac{1}{\\mathcal{N}} \\sum^7_{k=0} \\sin^2(0.25k+0.2) k \\approx 0.834.\n",
"$$"
Expand All @@ -65,16 +65,16 @@
"id": "c810e0d5-6fda-4868-aab9-ff036ff8974e",
"metadata": {},
"source": [
"## 1. Building the corresponding Grover Operator \n",
"## 1. Building the Corresponding Grover Operator \n",
"\n",
"### Quantum Functions\n",
"\n",
"The following example will demonstrate how to define QMOD functions by writing a Python function decorated with the `@qfunc` decorator.\n",
"This example demonstrates how to define Qmod functions by writing a Python function decorated with the `@qfunc` decorator.\n",
"The typical workflow for defining a quantum function:\n",
"1. Specifying the function signature: The `@qfunc` decorator relies on Python's type-hint mechanism to extract the signature of the QMOD function from the argument list of the Python function.\n",
"2. Specifying the function body: A function decorated with `@qfunc` is executed by the Python interpreter to construct the body of the QMOD function. Inside it, you can do one of the following:\n",
" - Call other `@qfuncs` to insert the corresponding quantum function calls into the body of the resulting QMOD function\n",
" - Introduce local quantum variables, by instantiating a quantum type\n",
"1. Specifying the function signature: The `@qfunc` decorator relies on Python's type-hint mechanism to extract the signature of the Qmod function from the argument list of the Python function.\n",
"2. Specifying the function body: To construct the body of the Qmod function, the Python interpreter executes a function decorated with `@qfunc`. Inside, you can do one of these:\n",
" - Call other `@qfuncs` to insert the corresponding quantum function calls into the body of the resulting Qmod function\n",
" - Introduce local quantum variables by instantiating a quantum type\n",
" - Use arithmetic and in-place assignment operators to insert special quantum statements into the function\n",
" "
]
Expand All @@ -84,7 +84,7 @@
"id": "d259adad-9b69-4602-932b-97d98b546503",
"metadata": {},
"source": [
"We can start with relevant imports"
"We can start with relevant imports:"
]
},
{
Expand All @@ -106,25 +106,25 @@
"id": "c2be12ee-3d17-49df-a69f-efab41b60b29",
"metadata": {},
"source": [
"### Grover operator for QMCI\n",
"### Grover Operator for QMCI\n",
"\n",
"The Grover operator suitable for QMCI is defined as follows:\n",
"$$\n",
"Q\\equiv - S_{\\psi_1} A^{\\dagger} S_0 A,\n",
"$$\n",
"with $S_0$ and $S_{\\psi_1}$ being reflection operators around the zero state $|0\\rangle_n|0\\rangle$ and the good-state $|\\psi_1\\rangle$, respectively, and the function $A$ is defined in Eq. ([2](#mjx-eqn-2)).\n",
"\n",
"In subsections (1.1)-(1.3) below we build each of the quantum sub-functions, and then in subsection (1.4) we combine them to define a complete Grover operator. On the way we introduce several concepts of functional modeling which allow Classiq's Synthesis Engine to reach better optimized circuits. "
"In subsections (1.1)-(1.3) below we build each of the quantum sub-functions, and then in subsection (1.4) we combine them to define a complete Grover operator. On the way we introduce several concepts of functional modeling, which allow the Classiq synthesis engine to reach better optimized circuits. "
]
},
{
"cell_type": "markdown",
"id": "a2c31065-077a-475a-ba06-af9b10a396d5",
"metadata": {},
"source": [
"#### 1.1) The state loading $A$ function\n",
"#### 1.1) The State Loading $A$ Function\n",
"\n",
"We start with constructing the $A$ operator in Eq. ([2](#mjx-eqn-2)). We define a quantum function and give it the name `state_loading`"
"We start with constructing the $A$ operator in Eq. ([2](#mjx-eqn-2)). We define a quantum function and give it the name `state_loading`."
]
},
{
Expand All @@ -133,7 +133,7 @@
"metadata": {},
"source": [
"The function's signature declares two arguments: \n",
"1. A quantum register `io` declared as `QArray[QBit]` (an array of qubits with an unspecified size): will be used to represent the discretization of space\n",
"1. A quantum register `io` declared as `QArray[QBit]` (an array of qubits with an unspecified size) that is used to represent the discretization of space.\n",
"2. A quantum register `ind` of size 1 declared as `QBit` to indicate the good state. "
]
},
Expand All @@ -143,19 +143,19 @@
"metadata": {},
"source": [
"Next, we construct the logic flow of the `state_loading` function. \n",
"The function body consists of 2 quantum function calls: `load_probabilities` followed by `amplitude_loading`\n",
"The function body consists of two quantum function calls:\n",
"\n",
"- As can be seen from Eq. ([2](#mjx-eqn-2)), the `load_probabilities` function is constructed using Classiq's `inplace_prepare_state` function call on $n=3$ qubits with probabilities $p_i$ \n",
"- The `amplitude_loading` body consists of a function call to Classiq's `linear_pauli_rotations`. The `linear_pauli_rotations` is used to load the amplitude of the function $ f(x) = sin^2(0.25 x + 0.2) $.\n",
"1. As can be seen from Eq. ([2](#mjx-eqn-2)), the `load_probabilities` function is constructed using the Classiq `inplace_prepare_state` function call on $n=3$ qubits with probabilities $p_i$. \n",
"2. The `amplitude_loading` body calls the Classiq `linear_pauli_rotations` function. The `linear_pauli_rotations` loads the amplitude of the function $ f(x) = sin^2(0.25 x + 0.2) $.\n",
"\n",
" *Note: the amplitude should be $sin$ so the probability would be $sin^2$.*\n",
" *Note: The amplitude should be $sin$ so the probability is $sin^2$.*\n",
"\n",
" The function uses an auxiliary qubit that is utilized so that the desired probability will reflect on the auxiliary qubit if it is in the `|1>` state.\n",
" The function uses an auxiliary qubit that is utilized so that the desired probability reflects on the auxiliary qubit if it is in the `|1>` state.\n",
"\n",
" We will use the function with the Pauli Y matrix and enter the appropriate slope and offset to achieve the right parameters.\n",
" We use the function with the Pauli Y matrix and enter the appropriate slope and offset to achieve the right parameters.\n",
"\n",
"\n",
"We will define the probabilities according to our specific problem described by Eqs. ([3](#mjx-eqn-3)-[4](#mjx-eqn-4))"
"We define the probabilities according to the specific problem described by Eqs. ([3](#mjx-eqn-3)-[4](#mjx-eqn-4))."
]
},
{
Expand Down Expand Up @@ -200,7 +200,7 @@
"id": "d06ba0e3-bbac-45d4-8ff5-46158b4038c8",
"metadata": {},
"source": [
"To examine our function we define a quantum `main` function from which we can build a model, synthesize and view the quantum program created:"
"To examine our function we define a quantum `main` function from which we can build a model, synthesize, and view the quantum program created:"
]
},
{
Expand All @@ -214,9 +214,7 @@
{
"name": "stdout",
"output_type": "stream",
"text": [
""
]
"text": []
}
],
"source": [
Expand All @@ -237,9 +235,9 @@
"id": "59b38acb-9ca9-4cfd-b87a-4208c75c63ca",
"metadata": {},
"source": [
"#### 1.2) $S_{\\psi_1}$ function - The good state oracle\n",
"#### 1.2) $S_{\\psi_1}$ Function - The Good State Oracle\n",
"\n",
"The next quantum function we define is the one which reflects around the good state: any $n+1$ state in which the `ind` register is at state $|1\\rangle$. This function can be simply constructed with a ZGate on the `ind` register. \n"
"The next quantum function we define is the one that reflects around the good state: any $n+1$ state in which the `ind` register is at state $|1\\rangle$. This function can be constructed with a ZGate on the `ind` register. \n"
]
},
{
Expand All @@ -261,13 +259,13 @@
"id": "fcc22b6c-8c2d-4ac9-ba63-c66416d40af9",
"metadata": {},
"source": [
"#### 1.3) $S_{0}$ function - The Grover Diffuser\n",
"#### 1.3) $S_{0}$ Function - The Grover Diffuser\n",
"\n",
"In order to implement the Grover Diffuser we aim to perform a controlled-Z operation on the $|0>^n$ state.\n",
"To implement the Grover Diffuser we aim to perform a controlled-Z operation on the $|0>^n$ state.\n",
"\n",
"We can define a `zero_oracle` quantum function with the `io` and `ind` registers as its arguments. \n",
"\n",
"The `within_apply` operator takes two function arguments - compute and action, and invokes the sequence compute(), action(), and invert(compute()). Quantum objects that are allocated and prepared by compute are subsequently uncomputed and released.\n",
"The `within_apply` operator takes two function argumentscompute and actionand invokes the sequence `compute()`, `action()`, and `invert(compute())`. Quantum objects that are allocated and prepared by compute are subsequently uncomputed and released.\n",
"\n",
"The `control` condition is a logical expression over a quantum variable. Currently, expressions are restricted to the form `<var> == <classical-expression>`, where both `<var>` and `<classical-expression>` are integer types."
]
Expand Down Expand Up @@ -295,7 +293,7 @@
"id": "a8a9636f-0007-4ca8-98d5-6a1ce7002820",
"metadata": {},
"source": [
"One can verify that:\n",
"We can verify that\n",
"\\begin{eqnarray}\n",
"|00\\dots0\\rangle \\xrightarrow[{\\rm ctrl(-Z)(target=q_0, ctrl=q_1\\dots q_n)}]{} -|00\\dots0\\rangle, \\\\\n",
"|10\\dots0\\rangle \\xrightarrow[{\\rm ctrl(-Z)(target=q_0, ctrl=q_1\\dots q_n)}]{} |10\\dots0\\rangle, \\\\\n",
Expand All @@ -311,12 +309,12 @@
"id": "52d45da1-8090-4e60-beed-9e4b3c57d929",
"metadata": {},
"source": [
"#### 1.4) $Q$ function - The Grover operator\n",
"#### 1.4) $Q$ Function - The Grover Operator\n",
"\n",
"We can now define a complete Grover operator $Q\\equiv -S_{\\psi_1} A^{\\dagger} S_0 A$. We will do this in a single code block that will call the following:\n",
"We can now define a complete Grover operator $Q\\equiv -S_{\\psi_1} A^{\\dagger} S_0 A$. We do this in a single code block that calls the following:\n",
"1. The good state oracle (`good_state_oracle`)\n",
"2. THe inverse of the state preparation (`state_loading`)\n",
"3. The Diffuser (`zero_oracle`)\n",
"3. The diffuser (`zero_oracle`)\n",
"4. The state preparation (`state_loading`)\n",
" \n",
"*Note:*\n",
Expand Down Expand Up @@ -352,7 +350,7 @@
"id": "0f4ffdde-0c92-436a-a28c-65cf843162de",
"metadata": {},
"source": [
"##### Let us look at the `my_grover_operator` function we created"
"##### Let us look at the `my_grover_operator` function we created:"
]
},
{
Expand All @@ -366,9 +364,7 @@
{
"name": "stdout",
"output_type": "stream",
"text": [
""
]
"text": []
}
],
"source": [
Expand All @@ -394,30 +390,30 @@
"source": [
"## 2. Applying Amplitude Estimation (AE) with Quantum Phase Estimation (QPE)\n",
"\n",
"Below we apply a basic AE algorithm which is based on QPE. The idea behind this Algorithm is the following:\n",
"Here we apply a basic AE algorithm that is based on QPE. The idea behind this algorithm is the following:\n",
"\n",
"The state $A|0\\rangle_n|0\\rangle$ is spanned by two eigenvectors of our Grover operator $Q$, with the two corresponding eigenvalues\n",
"\\begin{equation}\n",
"\\tag{5}\n",
"\\lambda_{\\pm}=\\exp\\left(\\pm i2\\pi \\theta \\right), \\qquad \\sin^2 \\left(\\pi \\theta\\right)\\equiv a.\n",
"\\end{equation}\n",
"Therefore, if we apply a QPE on $A|0\\rangle_n|0\\rangle$ we will have these two eigenvalues encoded in the QPE register, however, both give the value of $a$, so there is no ambiguity here."
"Therefore, if we apply a QPE on $A|0\\rangle_n|0\\rangle$, we have these two eigenvalues encoded in the QPE register. However, both give the value of $a$, so there is no ambiguity."
]
},
{
"cell_type": "markdown",
"id": "225566be-8c41-4d7a-abc6-ef3bb83a885b",
"metadata": {},
"source": [
"To find $a$ we are going to build a simple quantum model: we apply $A$ on a quantum register of size $n+1$ initialized to zero, and then apply Classiq's QPE with the `my_grover_operator` we defined."
"To find $a$ we build a simple quantum model, applying $A$ on a quantum register of size $n+1$ initialized to zero, and then applying the Classiq QPE with the `my_grover_operator` we defined."
]
},
{
"cell_type": "markdown",
"id": "e0605069-5062-4f01-92f8-a6b599c7e4bd",
"metadata": {},
"source": [
"Below is the `main` function from which we can build our model and synthesize it. In particular, we define the output register `phase` as `QNum` to hold the phase register output of the QPE. We choose a QPE with phase register of size 3, governing the accuracy of our Phase-, and thus Amplitude-, Estimation. "
"Below is the `main` function from which we can build our model and synthesize it. In particular, we define the output register `phase` as `QNum` to hold the phase register output of the QPE. We choose a QPE with phase register of size 3, governing the accuracy of our phase-, and thus amplitude-, estimation. "
]
},
{
Expand All @@ -429,9 +425,7 @@
{
"name": "stdout",
"output_type": "stream",
"text": [
""
]
"text": []
}
],
"source": [
Expand Down Expand Up @@ -463,7 +457,7 @@
"id": "14f3bf9f-4740-4849-896d-b9cb0dd064cb",
"metadata": {},
"source": [
"We can simply export our model to a `.qmod` file:"
"We can export our model to a `.qmod` file:"
]
},
{
Expand All @@ -481,9 +475,9 @@
"id": "94b452a3-7a47-440d-9c9a-bf88c9f5d3fd",
"metadata": {},
"source": [
"### Finally, we execute the circuit and measure the approximated amplitude\n",
"### Executing the Circuit and Measuring the Approximated Amplitude\n",
"\n",
"We start with a simple execution on a simulator"
"We execute on a simulator:"
]
},
{
Expand Down Expand Up @@ -525,7 +519,7 @@
"id": "cee12720-1205-40d6-970f-eb36e76911ad",
"metadata": {},
"source": [
"Plotting the resulting histogram we see two phase values with high probability (however, both corresponds to the same amplitude $a$)"
"Upon plotting the resulting histogram we see two phase values with high probability (however, both correspond to the same amplitude $a$):"
]
},
{
Expand Down Expand Up @@ -565,7 +559,7 @@
"id": "e75fe2d0-3e27-48e6-b8ee-0b9a33b7eb12",
"metadata": {},
"source": [
"Recall the relation in Eq. ([5](#mjx-eqn-5)), we can read the amplitude $a$ from the phase with max probability, and compare to the expected amplitude:"
"Recalling the relation in Eq. ([5](#mjx-eqn-5)), we can read the amplitude $a$ from the phase with maximum probability and compare to the expected amplitude:"
]
},
{
Expand Down

0 comments on commit a0fa141

Please sign in to comment.