diff --git a/QQuantLib/AE/ae_classical_qpe.py b/QQuantLib/AE/ae_classical_qpe.py index 9f5281b..8b6d6be 100644 --- a/QQuantLib/AE/ae_classical_qpe.py +++ b/QQuantLib/AE/ae_classical_qpe.py @@ -67,16 +67,16 @@ def __init__(self, oracle: qlm.QRoutine, target: list, index: list, **kwargs): self._oracle = oracle self._target = check_list_type(target, int) self._index = check_list_type(index, int) - + self.kwargs = kwargs # Set the QPU to use - self.linalg_qpu = kwargs.get("qpu", None) + self.linalg_qpu = self.kwargs.get("qpu", None) if self.linalg_qpu is None: - print("Not QPU was provide. PyLinalg will be used") - self.linalg_qpu = get_qpu("python") - self.auxiliar_qbits_number = kwargs.get("auxiliar_qbits_number", 8) - self.shots = int(kwargs.get("shots", 100)) + raise ValueError("Not QPU was provided") + self.auxiliar_qbits_number = self.kwargs.get( + "auxiliar_qbits_number", None) + self.shots = self.kwargs.get("shots") - self.mcz_qlm = kwargs.get("mcz_qlm", True) + self.mcz_qlm = self.kwargs.get("mcz_qlm", True) # First thing is create the grover operator from the oracle self._grover_oracle = grover( self.oracle, self.target, self.index, mcz_qlm=self.mcz_qlm @@ -183,15 +183,19 @@ def run(self): """ start = time.time() self.circuit_statistics = {} - dict_pe_qft = { + # dict_pe_qft = { + # "initial_state": self.oracle, + # "unitary_operator": self._grover_oracle, + # "auxiliar_qbits_number": self.auxiliar_qbits_number, + # "shots": self.shots, + # "qpu": self.linalg_qpu, + # } + self.kwargs.update({ "initial_state": self.oracle, "unitary_operator": self._grover_oracle, - "auxiliar_qbits_number": self.auxiliar_qbits_number, - "shots": self.shots, - "qpu": self.linalg_qpu, - } + }) - self.cqpe = CQPE(**dict_pe_qft) + self.cqpe = CQPE(**self.kwargs) self.cqpe.run() step_circuit_stats = self.cqpe.circuit.to_circ().statistics() step_circuit_stats.update({"n_shots": self.shots}) diff --git a/QQuantLib/PE/__init__.py b/QQuantLib/PE/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/QQuantLib/PE/classical_qpe.py b/QQuantLib/PE/classical_qpe.py index 14fbf86..e76a99c 100644 --- a/QQuantLib/PE/classical_qpe.py +++ b/QQuantLib/PE/classical_qpe.py @@ -21,6 +21,11 @@ from QQuantLib.qpu.get_qpu import get_qpu from QQuantLib.utils.utils import load_qn_gate from QQuantLib.utils.data_extracting import get_results +from QQuantLib.DL.data_loading import uniform_distribution +from QQuantLib.PE.windows_pe import window_selector +from qat.lang.AQASM.gates import ParamGate +from qat.lang.AQASM.routines import QRoutine + class CQPE: """ @@ -58,23 +63,54 @@ def __init__(self, **kwargs): # Setting attributes # In this case we load directly the initial state # and the grover operator - self.initial_state = kwargs.get("initial_state", None) - self.q_gate = kwargs.get("unitary_operator", None) + self.kwargs = kwargs + self.initial_state = self.kwargs.get("initial_state", None) + self.q_gate = self.kwargs.get("unitary_operator", None) if (self.initial_state is None) or (self.q_gate is None): text = "initial_state and grover keys should be provided" raise KeyError(text) # Number Of classical bits for estimating phase - self.auxiliar_qbits_number = kwargs.get("auxiliar_qbits_number", 8) + self.auxiliar_qbits_number = self.kwargs.get("auxiliar_qbits_number", None) + if self.auxiliar_qbits_number is None: + raise ValueError("Auxiliary number of qubits not provided") # Set the QPU to use - self.linalg_qpu = kwargs.get("qpu", None) + self.linalg_qpu = self.kwargs.get("qpu", None) if self.linalg_qpu is None: - print("Not QPU was provide. PyLinalg will be used") - self.linalg_qpu = get_qpu("python") + raise ValueError("Not QPU was provided") + + self.shots = self.kwargs.get("shots", None) + if self.shots is None: + print( + "Be Aware: Not shots povided! \ + Exact simulation (shots=0) will be used" + ) + self.complete = self.kwargs.get("complete", False) + + # Set the window function to use + self.window = self.kwargs.get("window", None) + # Change the sign in the last control + if self.window is None: + self.window_gate = uniform_distribution(self.auxiliar_qbits_number) + self.last_control_change = False + else: + if type(self.window) in [ParamGate, QRoutine]: + self.window_gate = self.window + self.last_control_change = self.kwargs.get( + "last_control_change", None) + if self.last_control_change is None: + raise ValueError( + "If you provide a window AbstractGate \ + last_control_change key CAN NOT BE NONE" + ) + elif type(self.window) is str: + self.window_gate, self.last_control_change = window_selector( + self.window, **self.kwargs + ) + else: + raise ValueError("Window kwarg not ParamGate neither QRoutine") - self.shots = kwargs.get("shots", 10) - self.complete = kwargs.get("complete", False) #Quantum Routine for QPE #Auxiliar qbits @@ -101,15 +137,31 @@ def run(self): qpe_routine.apply(self.initial_state, self.registers) #Creates the auxiliary qbits for phase estimation self.q_aux = qpe_routine.new_wires(self.auxiliar_qbits_number) + # Apply the window function to auxiliary qubits + # BE AWARE: the probability of the window function + # Should be loaded taking as a domain the Int_lsb!!! + qpe_routine.apply(self.window_gate, self.q_aux) #Apply controlled Operator an increasing number of times - for i, aux in enumerate(self.q_aux): + for i, aux in enumerate(self.q_aux[:-1]): #Apply Haddamard to all auxiliary qbits - qpe_routine.apply(qlm.H, aux) + #qpe_routine.apply(qlm.H, aux) #Power of the unitary operator depending of the position #of the auxiliary qbit. step_q_gate = load_qn_gate(self.q_gate, 2**i) #Controlled application of power of unitary operator qpe_routine.apply(step_q_gate.ctrl(), aux, self.registers) + # Las Control depends on the type of Window function applied + if self.last_control_change: + step_q_gate = load_qn_gate( + self.q_gate.dag(), + 2**(self.auxiliar_qbits_number - 1) + ) + else: + step_q_gate = load_qn_gate( + self.q_gate, + 2**(self.auxiliar_qbits_number - 1) + ) + qpe_routine.apply(step_q_gate.ctrl(), self.q_aux[-1], self.registers) #Apply the QFT qpe_routine.apply(qlm.qftarith.QFT(len(self.q_aux)).dag(), self.q_aux) self.circuit = qpe_routine @@ -128,6 +180,7 @@ def run(self): end = time.time() self.quantum_times.append(end-start) del self.result["Amplitude"] + # Transform to lambda. BE AWARE we need to use Int column self.result["lambda"] = self.result["Int"] / (2**len(self.q_aux)) diff --git a/QQuantLib/PE/windows_pe.py b/QQuantLib/PE/windows_pe.py new file mode 100644 index 0000000..0d51014 --- /dev/null +++ b/QQuantLib/PE/windows_pe.py @@ -0,0 +1,185 @@ +""" +This module contains different window functions. Based on: + Effects of cosine tapering window on quantum phase estimation. + Rendon, Gumaro and Izubuchi, Taku and Kikuchi, Yuta + Phys. Rev. D, 106. 2022 +Author: Gonzalo Ferro Costas +""" + +import numpy as np +import pandas as pd +from scipy.special import i0 +import qat.lang.AQASM as qlm +from QQuantLib.DL.data_loading import load_probability + +@qlm.build_gate("cosinewindow", [int], arity=lambda x: x) +def cosine_window(number_qubits: int): + """ + Creates a QLM AbstractGate for loading a Cosine Window Function + into a quantum state. + + Parameters + ---------- + number_qubits : int + Number of qubits for the quantum AbstractGate + + Return + ---------- + + window_state: AbstractGate + AbstractGate for loading a cosine + """ + + window_state = qlm.QRoutine() + q_bits = window_state.new_wires(number_qubits) + window_state.apply(qlm.H, q_bits[-1]) + window_state.apply( + qlm.qftarith.QFT(number_qubits), + q_bits + ) + for i, qb in enumerate(q_bits[:-1]): + window_state.apply(qlm.PH(-np.pi * 2 ** i / 2**number_qubits), qb) + window_state.apply( + qlm.PH(np.pi * (2 ** (number_qubits -1)) / 2 ** number_qubits), + q_bits[-1] + ) + #window_state.apply(qlm.X, q_bits[0]) + return window_state + +@qlm.build_gate("sinewindow", [int], arity=lambda x: x) +def sine_window(number_qubits: int): + """ + Creates a QLM AbstractGate for loading a Sine Window Function + into a quantum state. + + Parameters + ---------- + number_qubits : int + Number of qubits for the quantum AbstractGate + + Return + ---------- + + window_state: AbstractGate + AbstractGate for loading a sine + """ + window_state = qlm.QRoutine() + q_bits = window_state.new_wires(number_qubits) + window_state.apply(qlm.H, q_bits[-1]) + window_state.apply( + qlm.qftarith.QFT(number_qubits), + q_bits + ) + for i, qb in enumerate(q_bits[:-1]): + window_state.apply(qlm.PH(-np.pi * 2 ** i / 2**number_qubits), qb) + window_state.apply( + qlm.PH(np.pi * (2 ** (number_qubits -1)) / 2 ** number_qubits), + q_bits[-1] + ) + window_state.apply(qlm.X, q_bits[-1]) + return window_state + +def kaiser_array(number_qubits, alpha=1.0e-5): + """ + Creates the probability discretization of a Kaiser window function + for a given input of number of qubits and a alpha + Parameters + ---------- + number_qubits : int + Number of qubits for building the Kaiser window function + alpha : float + Parameter for modified Bessel function or order 0. + + Return + ---------- + + pdf: pandas DataFrame + pandas DF with the probability discretization of the Kaiser + window function + """ + # Integer domain: + domain_int = np.array(range(-2**(number_qubits-1), 2**(number_qubits-1))) + x_ = domain_int / 2 ** (number_qubits-1) + x_ = np.sqrt(1 - x_ ** 2) + y_ = i0(np.pi * alpha * x_) / i0(np.pi * alpha) + y_ = y_ / 2 ** number_qubits + y_ = y_ ** 2 + # Final Probability to load + y_final = y_ / np.sum(y_) + pdf = pd.DataFrame([domain_int, y_final]).T + pdf.rename(columns={0: "Int_neg", 1: "Prob"}, inplace=True) + # Change to positive integers + pdf["Int"] = np.where( + pdf["Int_neg"] < 0, + 2 ** number_qubits + pdf["Int_neg"], + pdf["Int_neg"] + ) + # Sort by positive integers + pdf.sort_values(["Int"], inplace=True) + pdf.reset_index(drop=True, inplace=True) + return pdf + +def kaiser_window(number_qubits, alpha=1.0e-5): + """ + Creates a QLM AbstractGate for loading a Kaiser Window Function + into a quantum state. Uses load_probability function for loading + the discretization of the probability of the Kaiser window function. + + Parameters + ---------- + number_qubits : int + Number of qubits for the quantum AbstractGate + alpha : float + Parameter for modified Bessel function or order 0. + + Return + ---------- + + kaiser_state: AbstractGate + AbstractGate for loading a Kaiser Window + """ + pdf = kaiser_array(number_qubits, alpha=alpha) + kaiser_state = load_probability(pdf["Prob"], id_name="KaiserWindow") + return kaiser_state + +def window_selector(window_type, **kwargs): + """ + Selector funcion for window functions + + Parameters + ---------- + window_type : str + String with the desired Window function + kwargs : keyword arguments + Keyword arguments for configuring window functions. Mandatory: + auxiliar_qbits_number. For Kaiser window it is mandatory to + provide kaiser_alpha + + Return + ---------- + + window gate: AbstractGate + AbstractGate with the desired window function + last_control_change : Bool + last_control_change value + """ + number_qubits = kwargs.get("auxiliar_qbits_number", None) + if number_qubits is None: + raise ValueError("auxiliar_qbits_number is None") + + if window_type in ["Cosine", "cosine", "cos"]: + return cosine_window(number_qubits), True + elif window_type in ["Sine", "sine", "sin"]: + return sine_window(number_qubits), False + elif window_type in ["Kaiser", "kaiser", "kais"]: + kaiser_alpha = kwargs.get("kaiser_alpha", None) + if kaiser_alpha is None: + raise ValueError("kaiser_alpha not provided") + return kaiser_window(number_qubits, kaiser_alpha), True + else: + raise ValueError( + "Incorrect window_type provided. Only valid \ + [Cosine, cosine, cos] for cosine window, \ + [Sine,sine, sin] for sine window \ + [Kaiser, kaiser, kais] for Kaiser window" + ) diff --git a/QQuantLib/finance/__init__.py b/QQuantLib/finance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 48a916d..7ff5ef7 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ A series of Jupyter notebooks have been developed in the **misc/notebooks** fold In the benchmark folder, three Python packages are presented to assess the performance of various quantum algorithms: -1. **compare_ae_probability**: This package enables easy configuration of different amplitude estimation algorithms and their application to a simple amplitude estimation problem (this is getting the probability of a fixed state when a probability density array is loaded into a quantum circuit). -2. **q_ae_price**: This package simplifies the configuration of price estimation problems for different financial derivatives (call and put options, and futures) and solves them using various configurations of quantum amplitude estimation algorithms. +1. **compare_ae_probability**: This package enables easy configuration of different amplitude estimation algorithms and their application to a simple amplitude estimation problem (this is getting the probability of a fixed state when a probability density array is loaded into a quantum circuit). For comparison between AE methods please review notebook CompareAEalgorithmsOnPureProbability.ipynb. +2. **q_ae_price**: This package simplifies the configuration of price estimation problems for different financial derivatives (call and put options, and futures) and solves them using various configurations of quantum amplitude estimation algorithms. For comparison between AE algorithms please refer to: *Compare_AE_algorithms_On_PriceEstimation.ipynb* 3. **qml4var**: This package allows to the user trains **PQC** that can be used as surrogate models of time consuming financial distribution functions. ## Acknowledgements diff --git a/benchmark/compare_ae_probability/jsons/ae_configuration_cqpeae.json b/benchmark/compare_ae_probability/jsons/ae_configuration_cqpeae.json index dc3ddbf..7568373 100644 --- a/benchmark/compare_ae_probability/jsons/ae_configuration_cqpeae.json +++ b/benchmark/compare_ae_probability/jsons/ae_configuration_cqpeae.json @@ -7,6 +7,8 @@ "ns": [null], "auxiliar_qbits_number": [10, 12, 14, 16], + "window" : [null], + "kaiser_alpha" : [null], "cbits_number": [null], diff --git a/benchmark/q_ae_price/jsons/cqpeae_configuration.json b/benchmark/q_ae_price/jsons/cqpeae_configuration.json new file mode 100644 index 0000000..ca950a1 --- /dev/null +++ b/benchmark/q_ae_price/jsons/cqpeae_configuration.json @@ -0,0 +1,32 @@ +[ + { + "ae_type": ["CQPEAE"], + "file": ["CQPEAE"], + + "schedule": [null], + "delta": [null], + "ns": [null], + + "auxiliar_qbits_number": [10, 12, 14, 16], + "window" : [null], + "kaiser_alpha" : [null], + + "cbits_number": [null], + + "epsilon": [null], + + "alpha": [null], + + "gamma": [null], + "q": [null], + + "erqae_schedule" :[null], + + "encoding" : [0], + "multiplexor": [true], + + "mcz_qlm": [false], + "shots": [100], + "number_of_tests": [null] + } +] diff --git a/misc/notebooks/04-02_Classical_Phase_Estimation_Windows.ipynb b/misc/notebooks/04-02_Classical_Phase_Estimation_Windows.ipynb new file mode 100644 index 0000000..cf29101 --- /dev/null +++ b/misc/notebooks/04-02_Classical_Phase_Estimation_Windows.ipynb @@ -0,0 +1,1814 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "91740961", + "metadata": {}, + "source": [ + "# Classical Phase Estimation (with QFT). Windows Initialization.\n", + "\n", + "$$\\newcommand{\\braket}[2]{\\left\\langle{#1}\\middle|{#2}\\right\\rangle}$$\n", + "$$\\newcommand{\\ket}[1]{\\left|{#1}\\right\\rangle}$$\n", + "$$\\newcommand{\\bra}[1]{\\left\\langle{#1}\\right|}$$" + ] + }, + { + "cell_type": "markdown", + "id": "c4f4d8f0", + "metadata": {}, + "source": [ + "This notebook explains how to use Windows initialization with classical Quantum Phase Estimation to enhance the probability of measuring the eigenvalues.\n", + "\n", + "This notebook uses the modules **QQuantLib/PE/windows_pe.py** and **QQuantLib/PE/classical_pe.py**.\n", + "\n", + "The present notebook is based on the following references:\n", + "\n", + "* *Gumaro Rendon, Taku Izubuchi and Yuta Kikuchi* (2021). Effects of Cosine Tapering Window on Quantum Phase Estimation. Phys. Rev. D **106**, https://link.aps.org/doi/10.1103/PhysRevD.106.034503\n", + "* *Sean Greenaway, William Pol and Sukin Sim* (2024). A case study against QSVT: assessment of quantum phase estimation improved by signal processing techniques. arXiv: https://arxiv.org/abs/2404.01396" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e06e916", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append(\"../../\")\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import qat.lang.AQASM as qlm\n", + "from QQuantLib.utils.data_extracting import get_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2699d475", + "metadata": {}, + "outputs": [], + "source": [ + "#This cell loads the QLM solver. QPU = [qlmass, python, c]\n", + "from QQuantLib.qpu.get_qpu import get_qpu\n", + "# myqlm qpus: python, c\n", + "# QLM qpus accessed using Qaptiva Access library: qlmass_linalg, qlmass_mps\n", + "# QLM qpus: Only in local Quantum Learning Machine: linalg, mps\n", + "my_qpus = [\"python\", \"c\", \"qlmass_linalg\", \"qlmass_mps\", \"linalg\", \"mps\"]\n", + "\n", + "linalg_qpu = get_qpu(my_qpus[1])" + ] + }, + { + "cell_type": "markdown", + "id": "f7302bed", + "metadata": {}, + "source": [ + "## 1. Vanilla QPE\n", + "\n", + "As explained in *04_Classical_Phase_Estimation_Class.ipynb* given a unitary operator $\\mathcal{Q}$ acting on an initial eigenestate $\\ket{\\Psi}$ such that:\n", + "\n", + "$$\\mathcal{Q} \\ket{\\Psi} = e^{2\\pi i\\theta}\\ket{\\Psi}$$\n", + "\n", + "the **QPE** algorithm allows us to estimate the eigenvalue $\\theta$.\n", + "\n", + "If the **QPE** algorithm is performed using $m$ auxiliary qubits the probability of measuring a state $\\ket{J}$ on them is given by:\n", + "\n", + "$$\\mathbf{P}_{\\ket{J}} = \\frac{1}{2^{2m}}\\frac{\\sin^2\\left( \\pi \\left(J-2^m \\theta\\right)\\right)}{\\sin^2\\left(\\frac{ \\pi}{2^m} \\left(J-2^m \\theta\\right)\\right)}$$\n", + "\n", + "Where $J={0, 1, \\cdots, 2^m-1}$.\n", + "\n", + "We can plot this probability function for $x=\\pi \\left(J-2^m \\theta\\right)$:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97e3276e", + "metadata": {}, + "outputs": [], + "source": [ + "m = 4\n", + "domain = np.linspace(0, np.pi, 1000)\n", + "p_x = (np.sin(domain))**2 /(2**(2*m) * (np.sin(domain/(2**m)))**2)\n", + "\n", + "plt.plot(domain, p_x)\n", + "plt.ylabel(\"Probability\")\n", + "plt.xlabel(r\"$x=\\pi \\left(J-2^m \\theta\\right)$\")" + ] + }, + { + "cell_type": "markdown", + "id": "dca334fc", + "metadata": {}, + "source": [ + "As can be seen, when $x=0 \\rightarrow J \\sim 2^m\\theta$ the probability is very high and decreases fast when $x \\neq 0$.\n", + "\n", + "In a quantum device, the $m$ measured auxiliary qubits are converted to a discrete value so we can only estimate $\\theta$ with precision equal to $\\frac{1}{2^m}$.\n", + "\n", + "So 2 different cases appear here:\n", + "1. The $\\theta$ eigenvalue has an exact representation using the $m$ qubits\n", + "2. The $\\theta$ eigenvalue has not an exact representation using the $m$ qubits" + ] + }, + { + "cell_type": "markdown", + "id": "7f5c59fe", + "metadata": {}, + "source": [ + "### 1.1 Exact $\\theta$\n", + "\n", + "In the case that $\\theta$ has an exact representation using the $m$ auxiliary qubits then the **QPE** algorithm will have probability of 1 of returning a state $\\ket{J}$ such that $J = 2^m \\theta$ \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "360636d2", + "metadata": {}, + "outputs": [], + "source": [ + "# Set Auxiliary qubits number\n", + "m = 4\n", + "# Posible integers\n", + "J_int = np.array(range(2**m))\n", + "J = np.linspace(0, 2**m, 100)\n", + "# Random selection of one of the posible integers\n", + "j_theta = np.random.randint(0, 2**m)\n", + "# Build an exact theta\n", + "theta = j_theta / 2**m\n", + "print(\"j_theta= {} , theta = {}\".format(j_theta, theta))\n", + "\n", + "#Theoretical Probability with floats\n", + "x = np.pi * (J - 2**m * theta)\n", + "p_j = np.sin(x) ** 2 / (2 ** (2 * m) * np.sin(x / (2 ** m)) ** 2)\n", + "\n", + "#Discrete probability in an ideal Quantum Device:\n", + "\n", + "x_int = np.pi * (J_int - 2**m * theta)\n", + "p_j_int = np.sin(x_int) ** 2 / (2 ** (2 * m) * np.sin(x_int / (2 ** m)) ** 2)\n", + "\n", + "plt.plot(J_int, p_j_int, 'o')\n", + "plt.plot(J, p_j, '-')\n", + "#plt.yscale(\"log\")\n", + "plt.legend([\"Quantum Device Output\", \"Theoretical Probability\"])\n", + "plt.ylabel(\"Probability\")\n", + "plt.xlabel(\"Measured J\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "569c058e", + "metadata": {}, + "outputs": [], + "source": [ + "# In this case is a NaN because the numerical probability is infinite!\n", + "J_int[np.isnan(p_j_int)]" + ] + }, + { + "cell_type": "markdown", + "id": "6bca166d", + "metadata": {}, + "source": [ + "### 1.2 Non Exact $\\theta$\n", + "\n", + "In the case that $\\theta$ can not be represented using the $m$ auxiliary qubits, **QPE** can always bound the estimations in the following way:\n", + "\n", + "$$\\theta \\in \\left[\\theta_j, \\theta_{j+1}\\right]$$\n", + "\n", + "where $\\theta_i = \\frac{i}{2^m}$. In this case the precision of the estimation will be: $\\frac{1}{2^m}$\n", + "\n", + "The probability of measurement $\\theta_j$ won't be 1 anymore. In fact, the worst case scenario is when $\\theta$ is just in the middle of $\\theta_j$ and $\\theta_{j+1}$ in this case the probability of measure $\\theta_j$ decreases to $\\frac{4}{\\pi^2} \\sim 0.4$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "610ff675", + "metadata": {}, + "outputs": [], + "source": [ + "m = 4\n", + "# Posible integers\n", + "int_j = np.array(range(2 ** m))\n", + "# Random selection of one of the posible integers\n", + "theta_ = np.random.randint(0, 2**m)\n", + "# Put theta in the midle of the interval \n", + "shift = 0.5\n", + "theta_half = (theta_ + shift) / 2 ** m\n", + "# Theoretical probs\n", + "float_j = np.linspace(0, 2 ** m, 2 ** m * 10)\n", + "domain_float = (float_j - 2 ** m * theta_half)\n", + "prob_float_j = np.sin(np.pi * domain_float) ** 2 / (2 ** (2 * m) * np.sin(np.pi * domain_float / (2 ** m)) ** 2)\n", + "# Quantum Device probabilities\n", + "domain_x = (int_j - 2**m * theta_half)\n", + "prob_int_j = np.sin(np.pi * domain_x) ** 2 / (2 ** (2 * m) * (np.sin(np.pi * domain_x / (2 ** m))) ** 2)\n", + "\n", + "plt.plot(int_j, prob_int_j, 'o')\n", + "plt.plot(float_j, prob_float_j, '-')\n", + "edge = 4 \n", + "#plt.xlim(2 ** m * theta_half - edge, 2 ** m * theta_half + edge)\n", + "plt.axvline(2 ** m * theta_half, color='g')\n", + "plt.xlabel(\"J\", fontsize=14)\n", + "plt.ylabel(r\"$P_{|J\\rangle}$\", fontsize=14)\n", + "plt.legend([\"Measurement\", \"Theoretical\"])\n", + "plt.title(\"J theoric = {}\".format(2 ** m *theta_half))" + ] + }, + { + "cell_type": "markdown", + "id": "45d7a967", + "metadata": {}, + "source": [ + "The main question is: \n", + "\n", + "**Can we increase this measurement probability when $\\theta$ is not exactly represented?**\n", + "\n", + "Indeed we can, using window functions over the $m$ auxiliary qubits of the **QPE** algorithm." + ] + }, + { + "cell_type": "markdown", + "id": "eb5b7598", + "metadata": {}, + "source": [ + "## 2. Boosting Probability using window functions\n", + "\n", + "\n", + "In the **QPE** algorithm the $m$ auxiliary qubits are initialized with **Haddamard** gates (*04_Classical_Phase_Estimation_Class.ipynb*). So, before the controlled applications gates, we have an equiprobable superposition of states. The window function techniques apply to these qubits a different initialization, so the probability of measuring a $\\theta_m$ can be boosted.\n", + "\n", + "\n", + "### 2.1 QPE with cosine window function. Theoric Probability.\n", + "\n", + "One possible initialization for the $m$ auxiliary qubits is a cosine Window function. In this case the superposition of the different states is not equiprobable and will follow a cosine distribution (so $P_{\\ket{0}} = \\frac{\\sqrt{2} \\cos(0)}{\\sqrt{2^m}}$, $P_{\\ket{1}} =\\frac{\\sqrt{2} \\cos(\\frac{\\pi 1}{2^m})}{\\sqrt{2^m}}$ and so on).\n", + "\n", + "In the case of a Cosine window initialization the **QPE** algorithm provides a probability of measuring the state $\\ket{J}$ in the auxiliary qubits that is given by:\n", + "\n", + "$$\\mathbf{P}^{cos}_{\\ket{J}} = \\frac{2}{2^{2m}} \\sum_{x=-2^{m-1}}^{2^{m-1}-1}\n", + "\\sum_{y=-2^{m-1}}^{2^{m-1}-1} \\cos\\left(\\frac{\\pi x}{2^m}\\right)\\cos\\left(\\frac{\\pi y}{2^m}\\right)\\cos\\left(\\frac{2 \\pi (J-2^m \\theta)(x-y)}{2^m}\\right)$$\n", + "\n", + "We can compare this probability with the obtained with the classical one when the $\\theta$ is in the middle of $\\theta_m$ and $\\theta_{m+1}$:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2244eaca", + "metadata": {}, + "outputs": [], + "source": [ + "def qpe_cosine(m, theta):\n", + " iterator = range(-2**(m-1), 2**(m-1)-1, 1)\n", + " final = []\n", + " for q in iterator:\n", + " suma = []\n", + " for x in iterator:\n", + " for y in iterator:\n", + " a = np.cos(np.pi * x / 2**m) * np.cos(np.pi * y / 2**m)\n", + " \n", + " \n", + " b = np.cos(2*np.pi*(q-2**m *theta) * (x-y) / 2**m)\n", + " suma.append(a*b)\n", + " final.append(np.sum(suma))\n", + " prob = np.array(final) *2 / (2**(2*m))\n", + " int_neg = np.array(iterator)\n", + " inte_positive = np.where(int_neg<0, int_neg+2**m, int_neg)\n", + " pdf = pd.DataFrame([prob, int_neg, inte_positive]).T\n", + " pdf.rename(columns={0:\"Prob\", 1: \"NegInt\", 2:\"PosInt\"}, inplace=True)\n", + " return pdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75d2f5e2", + "metadata": {}, + "outputs": [], + "source": [ + "y=qpe_cosine(m, theta_half)\n", + "plt.plot(float_j, prob_float_j, '-')\n", + "plt.plot(int_j, prob_int_j, 'o')\n", + "plt.plot(y[\"PosInt\"], y[\"Prob\"], 'o')\n", + "plt.legend([\"Theoric QPE\", \"QPE Haddamard\", \"QPE Cosine\"])\n", + "plt.ylabel(\"Probabilidad\")\n", + "plt.xlabel(\"Integer\")\n", + "plt.title(r\"$\\theta$ in the middle of the interval. Number of auxiliary qubits: {}. $\\theta =$ {}\".format(m, theta_half))" + ] + }, + { + "cell_type": "markdown", + "id": "efcc06ae", + "metadata": {}, + "source": [ + "As can be seen, the probability of obtaining $\\theta_m$, in this worst-case scenario, has increased from 0.4 (for Haddamard **QPE**) to 0.5 (for Cosine **QPE**)." + ] + }, + { + "cell_type": "markdown", + "id": "0d109d82", + "metadata": {}, + "source": [ + "### 2.2 Succes Probability and Failure Probability Definitions.\n", + "\n", + "The **success probability** is defined as the sum of the probabilities corresponding to the 2 nearest fixed points to $\\theta$. So, for a **QPE** with $m$ auxiliary qubits then \n", + "\n", + "$$\\theta \\in \\left[\\theta^m_j, \\theta^m_{j+1}\\right]$$ with $j=\\{0, 1, 2,\\cdots, 2^m-1\\}$\n", + "\n", + "Then \n", + "\n", + "$$P_{succes} = P(\\theta^m_j) + P(\\theta^m_{j+1})$$\n", + "\n", + "The **failure probability** will be defined as:\n", + "\n", + "$$P_{failure} = 1- P_{succes}$$\n", + "\n", + "\n", + "For a $m$ auxiliary qubits **QPE** if we perform a $m$-bit estimation of $\\theta$, $\\theta^{m,*}$, the probability of $|\\theta^{m,*}- \\theta| \\leq \\frac{1}{2^m}$ is given by $P_{succes}$:\n", + "\n", + "$$P_{succes} = P(\\theta^m_j) + P(\\theta^m_{j+1}) = P(|\\theta^{m,*}- \\theta| \\leq \\frac{1}{2^m})$$\n", + "\n", + "\n", + "In the case of classical **QPE** (this is **Haddamard** initialization) this **success probability** is given by: \n", + "\n", + "$$P_{succes} > \\frac{8}{\\pi^2} \\sim 0.81$$\n", + "\n", + "\n", + "### 2.3 Boosting Probability using additional qubits.\n", + "\n", + "One way of boosting this **success probability** for $m$ auxiliary qubits is using $p$ additional qubits so that the number of auxiliary qubits will be then $m+p$. Then when using the **QPE** algorithm, instead of creating a measurement histogram of $2 ^{m+p}$ bins, a histogram of $2^m$ bins will be built and the **success probability** of obtaining $|\\theta^{m,*}- \\theta| \\leq \\frac{1}{2^m}$ will be boosted over the original limit.\n", + "\n", + "For the **QPE** if we want a $P_{succes} = 1 - \\delta$ the theory says that the number of additional qubits required depends on the window function:\n", + "\n", + "1. Haddamard window function: $p \\sim \\log\\left(\\frac{1}{\\delta}\\right)$.\n", + "2. Cosine and Sine window functions: $p \\sim \\log\\left(\\frac{1}{\\delta^{\\frac{1}{3}}}\\right)$\n", + "3. Kaiser window functions: $p \\sim \\log\\log\\left(\\frac{1}{\\delta}\\right)$\n", + "\n", + "\n", + "The **CQPE** class from **QQuantLib/PE/classical_qpe** module allows the user to change the auxiliary qubit initialization for dealing with window functions. In the rest of the notebook, we explain how to provide windows functions to the **CQPE** class.\n" + ] + }, + { + "cell_type": "markdown", + "id": "ba35f866", + "metadata": {}, + "source": [ + "## 3. Pre-implemented Window functions\n", + "\n", + "Under the module **QQuantLib/PE/windows_pe** we have implemented three different windows functions:\n", + "\n", + "1. Cosine window\n", + "2. Sine window\n", + "3. Kaiser window\n", + "\n", + "Present section explains how to use them." + ] + }, + { + "cell_type": "markdown", + "id": "69f2156b", + "metadata": {}, + "source": [ + "### 3.1 Cosine Window function.\n", + "\n", + "When using a **Cosine Window** over $m$ qubits the state at the end will be:\n", + "\n", + "$$\\sum_{x=-2^{m-1}}^{2^{m-1}-1} \\frac{\\sqrt{2} \\cos\\left( \\frac{\\pi x}{2 ^m}\\right)}{\\sqrt{2^m}}\\ket{x}$$\n", + "\n", + "The **cosine_window** from **QQuantLib.PE.windows_pe** function creates an **AbstractGate** that implements this functionality into a quantum circuit given an input number of qubits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "922bccb1", + "metadata": {}, + "outputs": [], + "source": [ + "from QQuantLib.PE.windows_pe import cosine_window" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "722a37da", + "metadata": {}, + "outputs": [], + "source": [ + "auxiliar_qbits_number = 6\n", + "cos_win = cosine_window(auxiliar_qbits_number)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa5d3ddd", + "metadata": {}, + "outputs": [], + "source": [ + "#Quantum circuit implementation for cosine window\n", + "%qatdisplay cos_win --svg --depth 1" + ] + }, + { + "cell_type": "markdown", + "id": "714fb24b", + "metadata": {}, + "source": [ + "We can check that the cosine window is implemeted properly" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23349dac", + "metadata": {}, + "outputs": [], + "source": [ + "def cosine_array(m):\n", + " domain = np.array(range(2**m))\n", + " y = np.cos(np.pi * domain / len(domain))\n", + " y = y / np.sqrt(2**(m-1))\n", + " return y ** 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50d31455", + "metadata": {}, + "outputs": [], + "source": [ + "#theoric behaviour\n", + "array_cosine = cosine_array(auxiliar_qbits_number)\n", + "#quantum circuit behaviour\n", + "results,_,_,_ = get_results(cos_win, linalg_qpu=linalg_qpu, complete=True)" + ] + }, + { + "cell_type": "markdown", + "id": "3f025e5c", + "metadata": {}, + "source": [ + "#### BE AWARE\n", + "\n", + "When using window functions we are going to use the **Int_lsb** field of the output result dataframe as the correct domain!!!\n", + "\n", + "#### BE AWARE 2\n", + "\n", + "The domain definition of the cosine window state is between $-2^{m-1}$ and $2^{m-1}-1$. In the quantum circuit, the integers will go from $0$ to $2^m-1$. So the following changes can be made:\n", + "\n", + "\n", + "$$\\ket{y}= \\left\\{\n", + "\\begin{array}{ll}\n", + " \\ket{x=y} & \\left(0 \\leq y \\leq \\frac{2^m}{2} -1 \\right) \\\\\n", + " \\ket{x=y-2^m} & \\left(\\frac{2^m}{2} \\leq y \\leq 2^m -1 \\right) \\\\\n", + "\\end{array} \n", + "\\right.$$\n", + "\n", + "with $y \\in \\{0, 1, 2, \\cdots, 2^m-1\\}$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "453bd250", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(results[\"Int_lsb\"], results[\"Probability\"], 'o')\n", + "plt.plot(array_cosine)\n", + "plt.legend([\"Cosine Quantum Circuit\", \"Cosine Theoric\"])" + ] + }, + { + "cell_type": "markdown", + "id": "265f39f8", + "metadata": {}, + "source": [ + "### 3.2 Sine Window function.\n", + "\n", + "When using a **Sine Window** over $m$ qubits the state at the end will be:\n", + "\n", + "$$\\sum_{x=0}^{2^m-1}\n", + "\\sin\\left(\n", + "\\frac{\\pi x}{2^m +1}\n", + "\\right)\n", + "\\ket{x}\n", + "$$\n", + "\n", + "\n", + "The **sine_window** from **QQuantLib.PE.windows_pe** function creates an **AbstractGate** that implements this functionality into a quantum circuit given an input number of qubits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a262c15", + "metadata": {}, + "outputs": [], + "source": [ + "from QQuantLib.PE.windows_pe import sine_window" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "272248f9", + "metadata": {}, + "outputs": [], + "source": [ + "sin_win = sine_window(auxiliar_qbits_number)\n", + "#Quantum circuit implementation for sine window\n", + "%qatdisplay sin_win --svg --depth 1" + ] + }, + { + "cell_type": "markdown", + "id": "0aef02e6", + "metadata": {}, + "source": [ + "We can check that the sine window is implemeted properly" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fcb73ef", + "metadata": {}, + "outputs": [], + "source": [ + "def sine_array(m):\n", + " domain = np.array(range(2**m))\n", + " y = np.sin(np.pi * (domain) / len(domain)) / np.sqrt(2**(m-1))\n", + " return y ** 2" + ] + }, + { + "cell_type": "markdown", + "id": "18b4561e", + "metadata": {}, + "source": [ + "#### BE AWARE\n", + "\n", + "When using window functions we are going to use the **Int_lsb** field of the output result dataframe as the correct domain!!!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33a80e5c", + "metadata": {}, + "outputs": [], + "source": [ + "#theoric behaviour\n", + "array_sine = sine_array(auxiliar_qbits_number)\n", + "#quantum circuit behaviour\n", + "results_sine,_,_,_ = get_results(sin_win, linalg_qpu=linalg_qpu, complete=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44be55b8", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(results_sine[\"Int_lsb\"], results_sine[\"Probability\"], 'o')\n", + "plt.plot(array_sine)\n", + "plt.legend([\"Sine Quantum Circuit\", \"Sine Theoric\"])" + ] + }, + { + "cell_type": "markdown", + "id": "9e611e21", + "metadata": {}, + "source": [ + "### 3.3 Kaiser Window function.\n", + "\n", + "When using a **Kaiser Window** over $m$ qubits the state at the end will be:\n", + "\n", + "$$\\sum_{x=-2^{m-1}}^{2^{m-1}}\n", + "\\frac{1}{2^m}\n", + "\\frac{I_0 \\left(\\pi \\alpha \\sqrt{1-\\left(x/2^{m-1}\\right)^2} \\right)}{I_0(\\pi\\alpha)} \\ket{x}\n", + "$$\n", + "\n", + "Where $\\alpha$ is an input parameter and $I_0$ is the modified Bessel function of the first kind of order 0.\n", + "\n", + "The **kaiser_window** from **QQuantLib.PE.windows_pe** function creates an **AbstractGate** that implements this functionality into a quantum circuit given an input number of qubits and a parameter $\\alpha$.\n", + "\n", + "The **kaiser_window** uses the *load_probability* from **QQuantLib.DL** for loading the corresponding Kaiser probabilities. \n", + "\n", + "The **kaiser_array** from **QQuantLib.PE.windows_pe** creates these probabilities. This function returns a pandas DataFrame with the following columns:\n", + "\n", + "* **Int_neg**: the domain in positive and negative integers (this is the default domain presented in the formula)\n", + "* **Prob**: the probability of the Kaiser window function (this is the square of the Amplitudes of the formula properly normalized)\n", + "* **Int**: the domain but only in positive integers.\n", + "\n", + "To move between the completely positive integer domain and the positive and negative integers domain the following transformation must be used:\n", + "\n", + "$$\\ket{y}= \\left\\{\n", + "\\begin{array}{ll}\n", + " \\ket{x=y} & \\left(0 \\leq y \\leq \\frac{2^m}{2} -1 \\right) \\\\\n", + " \\ket{x=y-2^m} & \\left(\\frac{2^m}{2} \\leq y \\leq 2^m -1 \\right) \\\\\n", + "\\end{array} \n", + "\\right.$$\n", + "\n", + "with $y \\in \\{0, 1, 2, \\cdots, 2^m-1\\}$\n", + "\n", + "So the *Int_neg* column represents the $\\ket{x}$ basis and the *Int* column represents the $\\ket{y}$ basis.\n", + "\n", + "**BE AWARE**\n", + "\n", + "The order of the pandas DataFrame is given by the *Int* column so **IT IS NOT ORDERED USING THE DEFAULT DOMAIN**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f360106", + "metadata": {}, + "outputs": [], + "source": [ + "from QQuantLib.PE.windows_pe import kaiser_window, kaiser_array" + ] + }, + { + "cell_type": "markdown", + "id": "9374851f", + "metadata": {}, + "source": [ + "First we plot Kaiser function for different $\\alpha$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75a0ca7d", + "metadata": {}, + "outputs": [], + "source": [ + "#Plot the Kaiser probability using the default domain: positve and negative integer one\n", + "array_kaiser = kaiser_array(auxiliar_qbits_number, 0.001)\n", + "plt.plot(array_kaiser[\"Int_neg\"], array_kaiser[\"Prob\"], 'o')\n", + "array_kaiser = kaiser_array(auxiliar_qbits_number, 1)\n", + "plt.plot(array_kaiser[\"Int_neg\"], array_kaiser[\"Prob\"], 'o')\n", + "array_kaiser = kaiser_array(auxiliar_qbits_number, 10)\n", + "plt.plot(array_kaiser[\"Int_neg\"], array_kaiser[\"Prob\"], 'o')\n", + "plt.legend([r\"$\\alpha=0.001$\", r\"$\\alpha=1$\", r\"$\\alpha=10$\"])" + ] + }, + { + "cell_type": "markdown", + "id": "d402ad3a", + "metadata": {}, + "source": [ + "Now we can build the quantum circuit using the *kaiser_window* function. Under the hood this function uses the *kaiser_array* function for building the pandas DataFrame with the Kaiser window probabilities (properly normalized) and provide them to the *load_probability* function from **QQuantLib.DL** for building the corresponding Quantum Routine. The probability provided to the function are ordered following the *Int* column (this is completely positive integer domain). **BE AWARE** this is not the default order in the Kaiser window definition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "483e4e61", + "metadata": {}, + "outputs": [], + "source": [ + "kaiser_alpha = 20\n", + "gate_kaiser = kaiser_window(auxiliar_qbits_number, kaiser_alpha)\n", + "%qatdisplay gate_kaiser --svg --depth 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40959c4a", + "metadata": {}, + "outputs": [], + "source": [ + "array_kaiser = kaiser_array(auxiliar_qbits_number, kaiser_alpha)\n", + "results_kaiser,_,_,_ = get_results(\n", + " gate_kaiser, linalg_qpu=linalg_qpu, complete=True)" + ] + }, + { + "cell_type": "markdown", + "id": "b9ad3934", + "metadata": {}, + "source": [ + "#### BE AWARE\n", + "\n", + "When using window functions we are going to use the **Int_lsb** field of the output result dataframe as the correct domain!!!\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a1de2ac", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# We need to load the probability versus the positive integers domain.\n", + "plt.plot(results_kaiser[\"Int_lsb\"], results_kaiser[\"Probability\"], 'o')\n", + "plt.plot(array_kaiser[\"Prob\"])\n", + "plt.legend([\"Kaiser Quantum Circuit\", \"Kaiser Theoric\"])" + ] + }, + { + "cell_type": "markdown", + "id": "be21e479", + "metadata": {}, + "source": [ + "## 4. Using Window functions with CQPE class\n", + "\n", + "\n", + "The window functions can be used with the **CQPE** class from **QQuantLib.PE.classical_qpe** in an easy way. The only modification is added to the input dicitionary the *window* key. \n", + "\n", + "The following values can be provided to this *window* key:\n", + "\n", + "1. *AbstractGate* with the quantum implementation of loading the window function.\n", + "2. String. In this case, some of the pre implemented window AbstractGates are used.\n", + "\n", + "We are going to explain the different options but first we are going to set a simple **QPE** problem." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f616c134", + "metadata": {}, + "outputs": [], + "source": [ + "#Load Class\n", + "from QQuantLib.PE.classical_qpe import CQPE" + ] + }, + { + "cell_type": "markdown", + "id": "9194bb0c", + "metadata": {}, + "source": [ + "### 4.1 Setting QPE problem" + ] + }, + { + "cell_type": "markdown", + "id": "ab5a4b07", + "metadata": {}, + "source": [ + "#### Initial State" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a58797bf", + "metadata": {}, + "outputs": [], + "source": [ + "#initial state\n", + "n_qbits = 1\n", + "initial_state = qlm.QRoutine()\n", + "q_bits = initial_state.new_wires(n_qbits)\n", + "for i in range(n_qbits):\n", + " initial_state.apply(qlm.X, q_bits[i])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9563aa9e", + "metadata": {}, + "outputs": [], + "source": [ + "%qatdisplay initial_state --svg" + ] + }, + { + "cell_type": "markdown", + "id": "d297abf9", + "metadata": {}, + "source": [ + "#### Unitary Operator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "861eae37", + "metadata": {}, + "outputs": [], + "source": [ + "theta = np.random.random()\n", + "print(theta)\n", + "#Unitary Operator\n", + "unitary_operator = qlm.PH(theta * np.pi * 2) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13b18fa0", + "metadata": {}, + "outputs": [], + "source": [ + "%qatdisplay unitary_operator --svg" + ] + }, + { + "cell_type": "markdown", + "id": "6db75c04", + "metadata": {}, + "source": [ + "### 4.2 Window Function\n", + "\n", + "Now we are going to explain how to use window functions." + ] + }, + { + "cell_type": "markdown", + "id": "cdebc633", + "metadata": {}, + "source": [ + "#### 4.2.1 Original Behavior\n", + "\n", + "If not *window* key is provided the **Classical QPE** is used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d61f6335", + "metadata": {}, + "outputs": [], + "source": [ + "hadd_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + "}\n", + "hadd_qpe = CQPE(**hadd_dict)\n", + "hadd_qpe.run()\n", + "c_class = hadd_qpe.circuit\n", + "%qatdisplay c_class --svg --depth 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56fb1b80", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "eb329168", + "metadata": {}, + "source": [ + "#### 4.2.2 Providing an AbstractGate\n", + "\n", + "An AbstractGate that implements the desired window function should be passed to the *window* key of the input dictionary.\n", + "\n", + "**BE AWARE**\n", + "\n", + "The domain of the desired window function **MUST BE** the *Int_lsb* not the *Int*. If the window function loads a probability with domain *Int* the **QPE WON'T WORK**\n", + "\n", + "In addition to the *window* key another key should be provided to the input dictionary: the *last_control_change*.\n", + "\n", + "When the window function is defined over negative and positive integers (like Kaiser or Cosine) the value of this key **MUST BE** se to *True*. If the window function is defined over positive integers (like sine or the Haddamard) this should be set to *False* (this is the default behaviour).\n", + "\n", + "This is because the last controlled operation should be inverted when the function is defined over negative numbers.\n" + ] + }, + { + "cell_type": "markdown", + "id": "72881263", + "metadata": {}, + "source": [ + "##### Window Cosine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92e0199b", + "metadata": {}, + "outputs": [], + "source": [ + "#Cosine\n", + "auxiliar_qbits_number = 4\n", + "cosine_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': cosine_window(auxiliar_qbits_number),\n", + " \"last_control_change\": True, #Cosine defined over psoitive and negative ints\n", + "}\n", + "cos_qpe = CQPE(**cosine_dict)\n", + "cos_qpe.run()\n", + "c_cos = cos_qpe.circuit\n", + "%qatdisplay c_cos --svg --depth 1" + ] + }, + { + "cell_type": "markdown", + "id": "0ad8e347", + "metadata": {}, + "source": [ + "In the Cosine window, the default domain is in positive and negative integers so the last Controlled operator **MUST BE** $U^{-2^{m-1}}$ instead of $U^{2^{m-1}}$ (It can be seen that the last controlled Phase Gate has the opposite sign that the other ones)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1908f526", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(cos_qpe.result[\"lambda\"], cos_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE Cosine Window\"])\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "0fb42f5f", + "metadata": {}, + "source": [ + "##### Window Sine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "119e8df0", + "metadata": {}, + "outputs": [], + "source": [ + "#Sine\n", + "sine_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': sine_window(auxiliar_qbits_number),\n", + " \"last_control_change\": False, #Sine defined over positive ints\n", + "}\n", + "sin_qpe = CQPE(**sine_dict)\n", + "sin_qpe.run()\n", + "c_sin = sin_qpe.circuit\n", + "%qatdisplay c_sin --svg --depth 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a47e7e7", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "#plt.plot(cos_qpe.result[\"lambda\"], cos_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(sin_qpe.result[\"lambda\"], sin_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE sine Window\"])\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "0b6e6491", + "metadata": {}, + "source": [ + "##### Kaiser Window" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d84903f1", + "metadata": {}, + "outputs": [], + "source": [ + "# Kaiser Window\n", + "kaiser_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': kaiser_window(auxiliar_qbits_number, 1),\n", + " \"last_control_change\": True #Kaiser defined over positive and negative ints\n", + "}\n", + "kaiser_qpe = CQPE(**kaiser_dict)\n", + "kaiser_qpe.run()\n", + "c_kaiser = kaiser_qpe.circuit\n", + "%qatdisplay c_kaiser --svg --depth 0" + ] + }, + { + "cell_type": "markdown", + "id": "fc7a2ed8", + "metadata": {}, + "source": [ + "In the Kaiser window, the default domain is in positive and negative integers so the last Controlled operator **MUST BE** $U^{-2^{m-1}}$ instead of $U^{2^{m-1}}$ (It can be seen that the last controlled Phase Gate has the opposite sign that the other ones)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38df11e2", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(kaiser_qpe.result[\"lambda\"], kaiser_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE Kaiser Window\"])" + ] + }, + { + "cell_type": "markdown", + "id": "12bdedaa", + "metadata": {}, + "source": [ + "#### 4.2.2 Providing a string\n", + "\n", + "If the user wants to use one of the 3 pre-implemented window functions (cosine, sine or Kaiser) a string can be passed to the *window* key. In this case, the string can be:\n", + "\n", + "* \"Cosine\", \"cosine\", \"cos\": for using the Cosine window.\n", + "* \"Sine\", \"sine\", \"sin\": for using the Sine window\n", + "* \"Kaiser\", \"kaiser\", \"kais\": for using Kaiser window. In this case, an additional *kaiser_alpha* key with the desired $\\alpha$ should be provided.\n", + "\n", + "If a string is provided then the *last_control_change* is not mandatory anymore (code deals with this depending on the input string).\n" + ] + }, + { + "cell_type": "markdown", + "id": "d5476af9", + "metadata": {}, + "source": [ + "##### Window Cosine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7ba9e01", + "metadata": {}, + "outputs": [], + "source": [ + "#Cosine\n", + "auxiliar_qbits_number = 4\n", + "cosine_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Cosine\",\n", + " #\"last_control_change\": True, #Cosine defined over psoitive and negative ints\n", + "}\n", + "cos_qpe = CQPE(**cosine_dict)\n", + "cos_qpe.run()\n", + "c_cos = cos_qpe.circuit\n", + "%qatdisplay c_cos --svg --depth 1" + ] + }, + { + "cell_type": "markdown", + "id": "d8d6ab37", + "metadata": {}, + "source": [ + "In the Cosine window, the default domain is in positive and negative integers so the last Controlled operator **MUST BE** $U^{-2^{m-1}}$ instead of $U^{2^{m-1}}$ (It can be seen that the last controlled Phase Gate has the opposite sign that the other ones)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38dd58b6", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(cos_qpe.result[\"lambda\"], cos_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE Cosine Window\"])\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "d70064b0", + "metadata": {}, + "source": [ + "##### Window Sine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b22bd52", + "metadata": {}, + "outputs": [], + "source": [ + "#Sine\n", + "sine_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Sine\",\n", + " #\"last_control_change\": False, #Sine defined over positive ints\n", + "}\n", + "sin_qpe = CQPE(**sine_dict)\n", + "sin_qpe.run()\n", + "c_sin = sin_qpe.circuit\n", + "%qatdisplay c_sin --svg --depth 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96faa0a6", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "#plt.plot(cos_qpe.result[\"lambda\"], cos_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(sin_qpe.result[\"lambda\"], sin_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE sine Window\"])\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "f4d374e3", + "metadata": {}, + "source": [ + "##### Kaiser Window" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e23e4a84", + "metadata": {}, + "outputs": [], + "source": [ + "# Kaiser Window\n", + "kaiser_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Kaiser\",\n", + " \"kaiser_alpha\" : 1,\n", + " #\"last_control_change\": True #Kaiser defined over positive and negative ints\n", + "}\n", + "kaiser_qpe = CQPE(**kaiser_dict)\n", + "kaiser_qpe.run()\n", + "c_kaiser = kaiser_qpe.circuit\n", + "%qatdisplay c_kaiser --svg --depth 1" + ] + }, + { + "cell_type": "markdown", + "id": "af7b9aee", + "metadata": {}, + "source": [ + "In the Kaiser window, the default domain is in positive and negative integers so the last Controlled operator **MUST BE** $U^{-2^{m-1}}$ instead of $U^{2^{m-1}}$ (It can be seen that the last controlled Phase Gate has the opposite sign that the other ones)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f94f36cd", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hadd_qpe.result[\"lambda\"], hadd_qpe.result[\"Probability\"], 'o')\n", + "plt.plot(kaiser_qpe.result[\"lambda\"], kaiser_qpe.result[\"Probability\"], 'o')\n", + "plt.legend([\"QPE\", \"QPE Kaiser Window\"])\n", + "plt.axvline(theta, color=\"r\")" + ] + }, + { + "cell_type": "markdown", + "id": "8ca54f7e", + "metadata": {}, + "source": [ + "## 5. Boosting Succes Probability\n", + "\n", + "Now we can use the window functions for increasing the **success probability** for a fixed precision $\\epsilon = \\frac{1}{2^m}$. The procedure is:\n", + "\n", + "1. Fix a desired window function.\n", + "2. Fix the desired precision using $m$ qubits.\n", + "3. Execute **window QPE** with additional $p$ qubits.\n", + "4. The result will have $2^{m+p}$ posible solutions. We need to resample to the original $2^m$ solutions.\n", + "5. Compute the success probability using the resampled $2^m$ solutions.\n", + "\n", + "Instead of using the **success probability** we are going to use the **failure probability** (because it has better visualization but the conclusions are the same)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c2f6cfb", + "metadata": {}, + "outputs": [], + "source": [ + "import copy\n", + "# Function for resampling\n", + "def resample(pdf_, m, column_index=\"Int\"):\n", + " pdf = copy.deepcopy(pdf_)\n", + " # Create a DataSeries\n", + " pds = pdf[\"Probability\"]\n", + " # Set the index for the DataSeries\n", + " pds.index = pdf[column_index]\n", + " #print(pds)\n", + " pds.sort_index(inplace=True)\n", + " group_rows = len(pdf) // 2 ** m\n", + " pdf_resampled = pds.groupby(\n", + " np.arange(len(pdf_)) // group_rows\n", + " ).sum() \n", + " pdf_resampled = pd.DataFrame(pdf_resampled)\n", + " pdf_resampled[\"lambda\"] = pdf_resampled.index / len(pdf_resampled)\n", + " \n", + " return pdf_resampled\n", + "\n", + "# Compute failure probability\n", + "def success_probability(pds, theta, aux):\n", + " integer_ = int(theta * 2 ** aux) \n", + " return (pds <= integer_+1) & (pds >= integer_-1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34803d30", + "metadata": {}, + "outputs": [], + "source": [ + "# This will fix the precision\n", + "auxiliar_qbits_number = 4\n", + "# Additional qubits tested\n", + "list_of_ps = range(6)" + ] + }, + { + "cell_type": "markdown", + "id": "85617a05", + "metadata": {}, + "source": [ + "### 5.1 QPE Haddamard Window\n", + "\n", + "This is classical QPE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81affce8", + "metadata": {}, + "outputs": [], + "source": [ + "# Base dictionary\n", + "hadd_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'complete': True,\n", + " 'shots':0,\n", + "}\n", + "\n", + "failures_haddamard = []\n", + "list_of_ps = range(6)\n", + "\n", + "for p in list_of_ps:\n", + " # Updating the number of auxilary qubits\n", + " hadd_dict.update({\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number + p,\n", + " })\n", + " # Run QPE\n", + " hadd_qpe = CQPE(**hadd_dict)\n", + " hadd_qpe.run()\n", + " # Results of QPE: 2^{auxiliar_qbits_number + p}\n", + " pdf_hadd = hadd_qpe.result\n", + " # Resampled to 2^{auxiliar_qbits_number}\n", + " resampled_had = resample(pdf_hadd, auxiliar_qbits_number)\n", + " # Probability failure on 2^{auxiliar_qbits_number}\n", + " failure = 1.0-resampled_had[\n", + " success_probability(resampled_had.index, theta, auxiliar_qbits_number)\n", + " ][\"Probability\"].sum()\n", + " failures_haddamard.append(failure) \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e54bb853", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(list_of_ps, failures_haddamard, '-o')\n", + "plt.yscale(\"log\")\n", + "plt.xlabel(r\"Additional qubits ($p$)\")\n", + "plt.ylabel(\"Failure Probability\")\n", + "plt.title(r\"Failure probability. Precision: $\\frac{1}{2^m}$. m: \"+ str(auxiliar_qbits_number))" + ] + }, + { + "cell_type": "markdown", + "id": "0d1abf58", + "metadata": {}, + "source": [ + "### 5.2 QPE Cosine Window\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5609cbf0", + "metadata": {}, + "outputs": [], + "source": [ + "cos_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Cosine\"\n", + "}\n", + "\n", + "failures_cosine = []\n", + "for p in list_of_ps:\n", + " # Updating the number of auxilary qubits\n", + " cos_dict.update({\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number + p,\n", + " })\n", + " # Run QPE\n", + " cos_qpe = CQPE(**cos_dict)\n", + " cos_qpe.run()\n", + " # Results of QPE: 2^{auxiliar_qbits_number + p}\n", + " pdf_cos = cos_qpe.result\n", + " # Resampled to 2^{auxiliar_qbits_number}\n", + " resampled_cos = resample(pdf_cos, auxiliar_qbits_number)\n", + " # Probability failure on 2^{auxiliar_qbits_number}\n", + " failure = 1.0-resampled_cos[\n", + " success_probability(resampled_cos.index, theta, auxiliar_qbits_number)\n", + " ][\"Probability\"].sum()\n", + " failures_cosine.append(failure)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e512391d", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(list_of_ps, failures_haddamard, '-o')\n", + "plt.plot(list_of_ps, failures_cosine, '-o')\n", + "plt.yscale(\"log\")\n", + "plt.xlabel(r\"Additional qubits ($p$)\")\n", + "plt.ylabel(\"Failure Probability\")\n", + "plt.title(r\"Failure probability. Precision: $\\frac{1}{2^m}$. m: \"+ str(auxiliar_qbits_number))\n", + "plt.legend([\"Haddamard\", \"Cosine\"])" + ] + }, + { + "cell_type": "markdown", + "id": "20e2b6b7", + "metadata": {}, + "source": [ + "As can be seen, for the same number of additional qubits $p$ the **failure probability** decreases more when using the **Cosine window QPE** than traditional **QPE**." + ] + }, + { + "cell_type": "markdown", + "id": "872049db", + "metadata": {}, + "source": [ + "### 5.3 QPE Sine Window\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7058540", + "metadata": {}, + "outputs": [], + "source": [ + "sin_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Sine\"\n", + "}\n", + "\n", + "failures_sine = []\n", + "for p in list_of_ps:\n", + " # Updating the number of auxilary qubits\n", + " sin_dict.update({\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number + p,\n", + " })\n", + " # Run QPE\n", + " sin_qpe = CQPE(**sin_dict)\n", + " sin_qpe.run()\n", + " # Results of QPE: 2^{auxiliar_qbits_number + p}\n", + " pdf_sin = sin_qpe.result\n", + " # Resampled to 2^{auxiliar_qbits_number}\n", + " resampled_sin = resample(pdf_sin, auxiliar_qbits_number)\n", + " # Probability failure on 2^{auxiliar_qbits_number}\n", + " failure = 1.0-resampled_sin[\n", + " success_probability(resampled_sin.index, theta, auxiliar_qbits_number)\n", + " ][\"Probability\"].sum()\n", + " failures_sine.append(failure)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c502c55f", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(list_of_ps, failures_haddamard, '-o')\n", + "plt.plot(list_of_ps, failures_cosine, 'o')\n", + "plt.plot(list_of_ps, failures_sine, '-')\n", + "plt.yscale(\"log\")\n", + "plt.xlabel(r\"Additional qubits ($p$)\")\n", + "plt.ylabel(\"Failure Probability\")\n", + "plt.title(r\"Failure probability. Precision: $\\frac{1}{2^m}$. m: \"+ str(auxiliar_qbits_number))\n", + "plt.legend([\"Haddamard\", \"Cosine\", \"Sine\"])" + ] + }, + { + "cell_type": "markdown", + "id": "32379689", + "metadata": {}, + "source": [ + "As can be seen, for the same number of additional qubits $p$ the **failure probability** decreases more when using the **Sine window QPE** than traditional **QPE** (Cosine and Sine windows have the same behavior)." + ] + }, + { + "cell_type": "markdown", + "id": "838667da", + "metadata": {}, + "source": [ + "### 5.4 Kaiser Window\n", + "\n", + "For the *Kaiser window* we are going to use the following $\\alpha$ (obtained from https://arxiv.org/abs/2404.01396):\n", + "\n", + "* $p=1$ $\\alpha=6$\n", + "* $p=2$ $\\alpha=13$\n", + "* $p=3$ $\\alpha=25$\n", + "* $p=4$ $\\alpha=51$\n", + "* $p=5$ $\\alpha=100$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bfd45eb", + "metadata": {}, + "outputs": [], + "source": [ + "kaiser_dict = {\n", + " 'initial_state': initial_state,\n", + " 'unitary_operator': unitary_operator,\n", + " 'qpu' : linalg_qpu,\n", + " 'complete': True,\n", + " 'shots':0,\n", + " 'window': \"Kaiser\"\n", + "}\n", + "\n", + "failures_kaiser = []\n", + "alphas = [0, 6, 13, 25, 51, 100]\n", + "\n", + "for p,a in zip(list_of_ps, alphas):\n", + " print(p, a)\n", + " # Updating the number of auxilary qubits\n", + " kaiser_dict.update({\n", + " 'auxiliar_qbits_number' : auxiliar_qbits_number + p,\n", + " 'kaiser_alpha' : a\n", + " }) \n", + " # Run QPE\n", + " kaiser_qpe = CQPE(**kaiser_dict)\n", + " kaiser_qpe.run()\n", + " pdf_kaiser_ = kaiser_qpe.result\n", + " # Results of QPE: 2^{auxiliar_qbits_number + p}\n", + " resampled_kaiser = resample(pdf_kaiser_, auxiliar_qbits_number)\n", + " # Probability failure on 2^{auxiliar_qbits_number}\n", + " failure = 1.0-resampled_kaiser[\n", + " success_probability(resampled_kaiser.index, theta, auxiliar_qbits_number)\n", + " ][\"Probability\"].sum()\n", + " failures_kaiser.append(failure) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94463f09", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(list_of_ps, failures_haddamard, '-o')\n", + "plt.plot(list_of_ps, failures_cosine, 'o')\n", + "plt.plot(list_of_ps, failures_sine, '-')\n", + "plt.plot(list_of_ps, failures_kaiser, '-o')\n", + "plt.yscale(\"log\")\n", + "plt.xlabel(r\"Additional qubits ($p$)\")\n", + "plt.ylabel(\"Failure Probability\")\n", + "plt.title(r\"Failure probability. Precision: $\\frac{1}{2^m}$. m: \"+ str(auxiliar_qbits_number))\n", + "plt.legend([\"Haddamard\", \"Cosine\", \"Sine\", \"Kaiser\"])" + ] + }, + { + "cell_type": "markdown", + "id": "56738cb1", + "metadata": {}, + "source": [ + "As can be seen, a well configured *Kaiser* window (i.e. selected a properly $\\alpha$) provides a lower failure probability for the same number of additional qubits than *Cosine* (*Sine*) windows and thant traditional **QPE** ." + ] + }, + { + "cell_type": "markdown", + "id": "f41106ce", + "metadata": {}, + "source": [ + "## 6. Window QPE for QAE\n", + "\n", + "The Window QPE can be used for **Quantum Amplitude Estimation** straightforwardly. This section shows how to use it.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08089448", + "metadata": {}, + "outputs": [], + "source": [ + "from QQuantLib.DL.data_loading import load_probability\n", + "from QQuantLib.AA.amplitude_amplification import grover\n", + "from QQuantLib.AE.ae_classical_qpe import CQPEAE" + ] + }, + { + "cell_type": "markdown", + "id": "a0b15049", + "metadata": {}, + "source": [ + "Following cells creates the initial state $|\\Psi\\rangle = \\mathcal{A}|0\\rangle$" + ] + }, + { + "cell_type": "markdown", + "id": "bf5bfaf8", + "metadata": {}, + "source": [ + "### 6.1 Setting the AE problem\n", + "\n", + "First, we will define the following amplitude estimation problem:\n", + "\n", + "$$|\\Psi\\rangle = \\mathcal{A}|0\\rangle = \\dfrac{1}{\\sqrt{0+1+2+3+4+5+6+7+8}}\\left[\\sqrt{0}|0\\rangle+\\sqrt{1}|1\\rangle+\\sqrt{2}|2\\rangle+\\sqrt{3}|3\\rangle+\\sqrt{4}|4\\rangle+\\sqrt{5}|5\\rangle+\\sqrt{6}|6\\rangle+\\sqrt{7}|7\\rangle\\right] \\tag{2}$$\n", + "\n", + "The final state will be separated in the following way:\n", + "\n", + "$$|\\Psi\\rangle= \\mathcal{A}|0\\rangle = \\sqrt{a}|\\Psi_0\\rangle +\\sqrt{1-a}|\\Psi_1\\rangle,$$\n", + "\n", + "where:\n", + "\n", + "$$\\sqrt{a}|\\Psi_0\\rangle = \\sin(\\theta)|\\Psi_0\\rangle = \\dfrac{\\sqrt{1}}{\\sqrt{0+1+2+3+4+5+6+7+8}}|1\\rangle$$\n", + "\n", + "and \n", + "\n", + "$$\\sqrt{1-a}|\\Psi_1\\rangle = \\cos(\\theta)|\\Psi_1\\rangle = \\dfrac{1}{\\sqrt{0+1+2+3+4+5+6+7+8}}\\left[\\sqrt{0}|0\\rangle+\\sqrt{2}|2\\rangle+\\sqrt{3}|3\\rangle+\\sqrt{4}|4\\rangle+\\sqrt{5}|5\\rangle+\\sqrt{6}|6\\rangle+\\sqrt{7}|7\\rangle\\right].$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31207825", + "metadata": {}, + "outputs": [], + "source": [ + "#Here we created the mandatory oracle\n", + "n = 3\n", + "N = 2**n\n", + "x = np.arange(N)\n", + "probability = x/np.sum(x)\n", + "oracle = load_probability(probability)\n", + "\n", + "%qatdisplay oracle --depth 0 --svg\n", + "\n", + "#This will be the target state for grover and the list of qubits affected by Grover operator\n", + "target = [0, 0, 1]\n", + "index = range(oracle.arity)\n", + "\n", + "theoric_probability = probability[1]" + ] + }, + { + "cell_type": "markdown", + "id": "dcd6f674", + "metadata": {}, + "source": [ + "### 6.1 Traditional QPE\n", + "\n", + "For traditional QPE there is no change" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce37d257", + "metadata": {}, + "outputs": [], + "source": [ + "auxiliar_qbits_number = 8\n", + "#We create a python dictionary for configuration of class\n", + "hadd_dic = {\n", + " 'qpu': linalg_qpu,\n", + " 'auxiliar_qbits_number': auxiliar_qbits_number,\n", + " 'shots': 0,\n", + " 'complete':True\n", + "}\n", + "hadd_qae = CQPEAE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index, \n", + " **hadd_dic)\n", + "hadd_estimated = hadd_qae.run()\n", + "print(\"Estimation Haddamard: {}\".format(hadd_estimated))\n", + "print(\"theoric_probability: {}\".format(theoric_probability))\n", + "hadd_err = np.abs(hadd_estimated - theoric_probability)\n", + "print(\"Error for Haddamard QPE: {}\".format(hadd_err))" + ] + }, + { + "cell_type": "markdown", + "id": "b1b2a314", + "metadata": {}, + "source": [ + "### 6.2 Cosine Window QPE\n", + "\n", + "The input dictionary for the **CQPEAE** class will have the same keys than the **CQPE**." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20691baf", + "metadata": {}, + "outputs": [], + "source": [ + "#We create a python dictionary for configuration of class\n", + "cos_dic = {\n", + " 'qpu': linalg_qpu,\n", + " 'auxiliar_qbits_number': auxiliar_qbits_number,\n", + " 'shots': 0,\n", + " 'complete':True,\n", + " 'window': \"Cosine\"\n", + "}\n", + "cos_qae = CQPEAE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index, \n", + " **cos_dic)\n", + "cos_estimated = cos_qae.run()\n", + "print(\"Estimation Cosine Window: {}\".format(cos_estimated))\n", + "print(\"theoric_probability: {}\".format(theoric_probability))\n", + "cos_err = np.abs(cos_estimated - theoric_probability)\n", + "print(\"Error for Cosine QPE: {}\".format(cos_err))" + ] + }, + { + "cell_type": "markdown", + "id": "3d70f18a", + "metadata": {}, + "source": [ + "### 6.3 Sine Window QPE\n", + "\n", + "The input dictionary for the **CQPEAE** class will have the same keys than the **CQPE**." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc13be35", + "metadata": {}, + "outputs": [], + "source": [ + "#We create a python dictionary for configuration of class\n", + "sin_dic = {\n", + " 'qpu': linalg_qpu,\n", + " 'auxiliar_qbits_number': auxiliar_qbits_number,\n", + " 'shots': 0,\n", + " 'complete':True,\n", + " 'window': \"Sine\"\n", + "}\n", + "\n", + "sin_qae = CQPEAE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index, \n", + " **sin_dic)\n", + "sin_estimated = sin_qae.run()\n", + "print(\"Estimation Sine Window: {}\".format(sin_estimated))\n", + "print(\"theoric_probability: {}\".format(theoric_probability))\n", + "sin_err = np.abs(sin_estimated - theoric_probability)\n", + "print(\"Error for Sine QPE: {}\".format(sin_err))" + ] + }, + { + "cell_type": "markdown", + "id": "0d496095", + "metadata": {}, + "source": [ + "### 6.4 Kaiser Window QPE\n", + "\n", + "The input dictionary for the **CQPEAE** class will have the same keys than the **CQPE**." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b020953", + "metadata": {}, + "outputs": [], + "source": [ + "#We create a python dictionary for configuration of class\n", + "kaiser_dic = {\n", + " 'qpu': linalg_qpu,\n", + " 'auxiliar_qbits_number': auxiliar_qbits_number,\n", + " 'shots': 0,\n", + " 'complete':True,\n", + " 'window': \"Kaiser\",\n", + " 'kaiser_alpha' : 1.7# Could be different\n", + "}\n", + "\n", + "kaiser_qae = CQPEAE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index, \n", + " **kaiser_dic)\n", + "\n", + "kaiser_estimated = kaiser_qae.run()\n", + "print(\"Estimation Kaiser Window: {}\".format(kaiser_estimated))\n", + "print(\"theoric_probability: {}\".format(theoric_probability))\n", + "kaiser_err = np.abs(kaiser_estimated - theoric_probability)\n", + "print(\"Error for Kaiser QPE: {}\".format(kaiser_err))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/misc/notebooks/08_AmplitudeEstimation_Class.ipynb b/misc/notebooks/08_AmplitudeEstimation_Class.ipynb index 870c475..beb346c 100644 --- a/misc/notebooks/08_AmplitudeEstimation_Class.ipynb +++ b/misc/notebooks/08_AmplitudeEstimation_Class.ipynb @@ -405,7 +405,7 @@ "3. index: list of the qubits affected by the Grover operator.\n", "4. ae_type: str. String for selecting the algorithm to use. Valid values\n", " * **MLAE**: for using Maximum Likelihood algorithm (see Notebook 03_Maximum_Likelihood_Amplitude_Estimation_Class.ipynb)\n", - " * **CQPEAE**: for using classical Phase Estimation with Quantum Fourier Transformation (**QFT**) for **AE** (see Notebook 04_Classical_Phase_Estimation_Class.ipynb)\n", + " * **CQPEAE**: for using classical Phase Estimation with Quantum Fourier Transformation (**QFT**) for **AE** (see Notebook 04_Classical_Phase_Estimation_Class.ipynb). It can use window QPE (see Notebook 04-02_Classical_Phase_Estimation_Windows.ipynb)\n", " * **IQPEAE**: for using classical Phase Estimation with iterative Quantum Fourier Transformation (**QFT**) for **AE** (see Notebook 05_Iterative_Quantum_Phase_Estimation_Class.ipynb)\n", " * **IQAE**: for using Iterative Quantum Amplitude Estimation (see Notebook 06_Iterative_Quantum_Amplitude_Estimation_class.ipynb). The modified **IQAE** can be used by the **AE** class. We need to provided following string:\n", " * **mIQAE**\n", @@ -506,6 +506,9 @@ " \n", " #CQPEAE\n", " 'auxiliar_qbits_number': 10,\n", + " 'window' : None,\n", + " 'kaiser_alpha': None,\n", + " \n", " #IQPEAE\n", " 'cbits_number': 6,\n", " #IQAE & RQAQE\n", @@ -719,6 +722,8 @@ " \n", " #CQPEAE\n", " 'auxiliar_qbits_number': 10,\n", + " 'window' : None,\n", + " 'kaiser_alpha': None, \n", " #IQPEAE\n", " 'cbits_number': 6,\n", " #IQAE & RQAQE\n", @@ -895,41 +900,13 @@ "metadata": {}, "outputs": [], "source": [ - "m_k = [i for i in range(12)]\n", + "# Base Dictionary\n", "ae_dict = {\n", " #QPU\n", " 'qpu': linalg_qpu,\n", " #Multi controlled decomposition\n", " 'mcz_qlm': False, \n", - " \n", - " #shots\n", - " 'shots': 100,\n", - " \n", - " #MLAE\n", - " 'schedule': [\n", - " m_k,\n", - " [100]*len(m_k)\n", - " ],\n", - " 'delta' : 1.0e-6,\n", - " 'ns' : 10000,\n", - " \n", - " #CQPEAE\n", - " 'auxiliar_qbits_number': 10,\n", - " #IQPEAE\n", - " 'cbits_number': 6,\n", - " #IQAE & RQAQE\n", - " 'epsilon': 0.0001,\n", - " #IQAE\n", - " 'alpha': 0.05,\n", - " #RQAE\n", - " 'gamma': 0.05,\n", - " 'q': 1.2\n", - "}\n", - "ae_object = AE(\n", - " oracle=oracle,\n", - " target=target,\n", - " index=index,\n", - " **ae_dict)" + "}" ] }, { @@ -943,20 +920,28 @@ { "cell_type": "code", "execution_count": null, - "id": "4397ceb3", - "metadata": {}, - "outputs": [], - "source": [ - "ae_object.ae_type = 'MLAE'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b853a4ee", + "id": "a178688b", "metadata": {}, "outputs": [], "source": [ + "# Update with MLAE configuration\n", + "m_k = [i for i in range(12)]\n", + "ae_dict.update({\n", + " \"ae_type\":'MLAE',\n", + " #MLAE\n", + " 'schedule': [\n", + " m_k,\n", + " [100]*len(m_k)\n", + " ],\n", + " 'delta' : 1.0e-6,\n", + " 'ns' : 10000, \n", + "})\n", + "\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", "ae_object.run()" ] }, @@ -1039,7 +1024,19 @@ "metadata": {}, "outputs": [], "source": [ - "ae_object.ae_type = 'CQPEAE'\n", + "# Update with CQPEAE configuration\n", + "ae_dict.update({\n", + " \"ae_type\":'CQPEAE',\n", + " 'shots': 10000,\n", + " 'auxiliar_qbits_number': 10,\n", + " 'window' : None,\n", + " 'kaiser_alpha': None, \n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", "ae_object.run()\n", "cqpeae_result = ae_object.ae_pdf" ] @@ -1061,7 +1058,8 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"Absolute Error for CQPEAE: {}\".format(np.abs(cqpeae_result['ae'][0] - desired_result)))" + "print(\"Absolute Error for CQPEAE: {}\".format(\n", + " np.abs(cqpeae_result['ae'][0] - desired_result)))" ] }, { @@ -1087,22 +1085,78 @@ { "cell_type": "code", "execution_count": null, - "id": "e2f1a731", + "id": "6b102ce3", + "metadata": {}, + "outputs": [], + "source": [ + "print(ae_object.run_time)\n", + "print(ae_object.quantum_time)" + ] + }, + { + "cell_type": "markdown", + "id": "9c985bee", + "metadata": {}, + "source": [ + "#### 3.2.1 Window QPE\n", + "\n", + "The window **QPE** initialization of the auxiliary qubits can be provided easily" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56d01611", "metadata": {}, "outputs": [], "source": [ - "ae_object.schedule_pdf" + "ae_dict.update({\n", + " \"ae_type\":'CQPEAE',\n", + " 'auxiliar_qbits_number': 10,\n", + " 'shots': 10000,\n", + " \"window\": \"sine\",\n", + " 'kaiser_alpha': None, \n", + "})\n", + "\n", + "\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", + "ae_object.run()\n", + "cqpeae_result = ae_object.ae_pdf\n", + "\n", + "print(\"Absolute Error for CQPEAE: {}\".format(\n", + " np.abs(cqpeae_result['ae'][0] - desired_result)))" ] }, { "cell_type": "code", "execution_count": null, - "id": "6b102ce3", + "id": "9c5a014f", "metadata": {}, "outputs": [], "source": [ - "print(ae_object.run_time)\n", - "print(ae_object.quantum_time)" + "ae_dict.update({\n", + " \"ae_type\":'CQPEAE',\n", + " 'auxiliar_qbits_number': 10,\n", + " 'shots': 10000,\n", + " \"window\": \"Kaiser\",\n", + " 'kaiser_alpha': 2, \n", + "})\n", + "\n", + "\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", + "ae_object.run()\n", + "cqpeae_result = ae_object.ae_pdf\n", + "\n", + "print(\"Absolute Error for CQPEAE: {}\".format(\n", + " np.abs(cqpeae_result['ae'][0] - desired_result)))" ] }, { @@ -1120,7 +1174,16 @@ "metadata": {}, "outputs": [], "source": [ - "ae_object.ae_type = 'IQPEAE'\n", + "ae_dict.update({\n", + " \"ae_type\":'IQPEAE',\n", + " 'cbits_number': 6,\n", + " 'shots': 10,\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", "ae_object.run()\n", "iqpeae_result = ae_object.ae_pdf" ] @@ -1201,7 +1264,17 @@ "metadata": {}, "outputs": [], "source": [ - "ae_object.ae_type = 'IQAE'\n", + "ae_dict.update({\n", + " \"ae_type\":'IQAE',\n", + " 'epsilon': 0.0001,\n", + " 'alpha': 0.05,\n", + " 'shots': 1000,\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", "ae_object.run()\n", "iqae_result = ae_object.ae_pdf" ] @@ -1267,6 +1340,66 @@ "print(ae_object.quantum_time)" ] }, + { + "cell_type": "markdown", + "id": "99fe8e1a", + "metadata": {}, + "source": [ + "**mIQAE** can be used easily" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc0b028a", + "metadata": {}, + "outputs": [], + "source": [ + "ae_dict.update({\n", + " \"ae_type\":'mIQAE',\n", + " 'epsilon': 0.0001,\n", + " 'alpha': 0.05,\n", + " 'shots': 1000,\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", + "ae_object.run()\n", + "miqae_result = ae_object.ae_pdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81709205", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Absolute Error for IQAE: {}\".format(np.abs(miqae_result['ae'][0] - desired_result)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "daf93ebe", + "metadata": {}, + "outputs": [], + "source": [ + "ae_object.oracle_calls" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32937a57", + "metadata": {}, + "outputs": [], + "source": [ + "ae_object.schedule_pdf" + ] + }, { "cell_type": "markdown", "id": "0aaecc35", @@ -1293,7 +1426,18 @@ "metadata": {}, "outputs": [], "source": [ - "ae_object.ae_type = 'RQAE'\n", + "ae_dict.update({\n", + " \"ae_type\":'RQAE',\n", + " 'epsilon': 0.0001,\n", + " 'gamma': 0.05,\n", + " 'q': 2,\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", + "ae_object.run()\n", "ae_object.run()\n", "rqae_result = ae_object.ae_pdf" ] @@ -1367,6 +1511,77 @@ "print(ae_object.quantum_time)" ] }, + { + "cell_type": "markdown", + "id": "4def1709", + "metadata": {}, + "source": [ + "**mRQAE** can be used easily" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7e5215a", + "metadata": {}, + "outputs": [], + "source": [ + "ae_dict.update({\n", + " \"ae_type\":'mRQAE',\n", + " 'epsilon': 0.0001,\n", + " 'gamma': 0.05,\n", + " 'q': 2,\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", + "ae_object.run()\n", + "ae_object.run()\n", + "mrqae_result = ae_object.ae_pdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d6f0392", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Absolute Error for mRQAE: {}\".format(np.abs(mrqae_result['ae'][0]**2 -desired_result)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f08c93e8", + "metadata": {}, + "outputs": [], + "source": [ + "ae_object.oracle_calls" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54354753", + "metadata": {}, + "outputs": [], + "source": [ + "ae_object.max_oracle_depth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "533ad515", + "metadata": {}, + "outputs": [], + "source": [ + "ae_object.schedule_pdf" + ] + }, { "cell_type": "markdown", "id": "b00d9f78", @@ -1382,8 +1597,15 @@ "metadata": {}, "outputs": [], "source": [ - "ae_dict.update({'ae_type': 'MCAE'})\n", - "ae_dict.update({'shots': 1000})\n", + "ae_dict.update({\n", + " \"ae_type\":'MCAE',\n", + " 'shots': 1000\n", + "})\n", + "ae_object = AE(\n", + " oracle=oracle,\n", + " target=target,\n", + " index=index,\n", + " **ae_dict)\n", "\n", "ae_object = AE(\n", " oracle=oracle,\n", @@ -1470,9 +1692,9 @@ ], "metadata": { "kernelspec": { - "display_name": "myqlm_tes", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "myqlm_tes" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1484,7 +1706,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.14" + "version": "3.9.9" } }, "nbformat": 4, diff --git a/misc/notebooks/10_ApplicationTo_Finance_01_IntegralComputing.ipynb b/misc/notebooks/10_ApplicationTo_Finance_01_IntegralComputing.ipynb index 8fe9336..b714dad 100644 --- a/misc/notebooks/10_ApplicationTo_Finance_01_IntegralComputing.ipynb +++ b/misc/notebooks/10_ApplicationTo_Finance_01_IntegralComputing.ipynb @@ -268,6 +268,8 @@ " \n", " #CQPEAE\n", " 'auxiliar_qbits_number': 14,\n", + " \"window\" : None, \n", + " \"kaiser_alpha\" : None,\n", " #IQPEAE\n", " 'cbits_number': 10,\n", " #IQAE & RQAQE\n", @@ -600,30 +602,33 @@ }, { "cell_type": "markdown", - "id": "5e10fb13", + "id": "ce92c4d9", "metadata": {}, "source": [ "#This cell loads the QLM solver. QPU = [qlmass, python, c]\n", "from QQuantLib.qpu.get_qpu import get_qpu\n", "my_qpus = [\"python\", \"c\", \"qlmass_linalg\", \"qlmass_mps\", \"linalg\", \"mps\"]\n", "\n", - "linalg_qpu = get_qpu(my_qpus[2])" + "linalg_qpu = get_qpu(my_qpus[])" ] }, { "cell_type": "markdown", - "id": "2ac6cc47", + "id": "1cbcceb9", "metadata": {}, "source": [ "ae_dict.update({\"ae_type\" : \"CQPEAE\"})\n", "ae_dict.update({\"qpu\" : linalg_qpu})\n", "#When bigger more precision and more computing demand\n", - "ae_dict.update({\"auxiliar_qbits_number\" : 14})" + "ae_dict.update({\n", + " \"auxiliar_qbits_number\" : 12,\n", + " \"window\": \"sine\"\n", + "})" ] }, { "cell_type": "markdown", - "id": "c3406967", + "id": "e898bf28", "metadata": {}, "source": [ "cqpeae_solution, cqpeae_object = q_solve_integral(**ae_dict)" @@ -631,7 +636,7 @@ }, { "cell_type": "markdown", - "id": "3bb88f5e", + "id": "050cc159", "metadata": {}, "source": [ "cqpeae_rieman = cqpeae_solution*f_x_normalisation*p_x_normalisation\n", @@ -1752,9 +1757,9 @@ ], "metadata": { "kernelspec": { - "display_name": "myqlm_tes", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "myqlm_tes" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1766,7 +1771,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.14" + "version": "3.9.9" } }, "nbformat": 4, diff --git a/misc/notebooks/12_ApplicationTo_Finance_03_AEPriceEstimation.ipynb b/misc/notebooks/12_ApplicationTo_Finance_03_AEPriceEstimation.ipynb index f54f33d..4e75263 100644 --- a/misc/notebooks/12_ApplicationTo_Finance_03_AEPriceEstimation.ipynb +++ b/misc/notebooks/12_ApplicationTo_Finance_03_AEPriceEstimation.ipynb @@ -261,6 +261,9 @@ " \n", " #CQPEAE configuration\n", " 'auxiliar_qbits_number': 14,\n", + " \"window\" : None,\n", + " \"kaiser_alpha\" : None,\n", + " \n", " \n", " #IQPEAE configuration\n", " 'cbits_number': 10, \n",