diff --git a/tests/test_btc_01_pl.py b/tests/test_btc_01_pl.py index 9677416..5d0250e 100644 --- a/tests/test_btc_01_pl.py +++ b/tests/test_btc_01_pl.py @@ -11,7 +11,7 @@ sys.path.append(l_path) sys.path.append(l_path+"BTC_01_PL") from BTC_01_PL.my_benchmark_execution import KERNEL_BENCHMARK as PL_CLASS -from get_qpu import get_qpu +from PL.qpu.select_qpu import select_qpu def create_folder(folder_name): """ @@ -44,14 +44,35 @@ def create_folder(folder_name): def test_pl(): kernel_configuration = { "load_method" : "multiplexor", - "qpu" : "c", #python, qlmass, default "relative_error": None, "absolute_error": None } name = "PL_{}".format(kernel_configuration["load_method"]) print(os.getcwdb()) - kernel_configuration.update({"qpu": get_qpu(kernel_configuration['qpu'])}) - + # Naive qpu configuration + qpu_conf = { + "qpu_type": "c", + "t_gate_1qb" : None, + "t_gate_2qbs" : None, + "t_readout": None, + "depol_channel" : { + "active": False, + "error_gate_1qb" : None, + "error_gate_2qbs" : None + }, + "idle" : { + "amplitude_damping": False, + "dephasing_channel": False, + "t1" : None, + "t2" : None + }, + "meas": { + "active":False, + "readout_error": None + } + } + + kernel_configuration.update({"qpu": select_qpu(qpu_conf)}) benchmark_arguments = { #Pre benchmark configuration "pre_benchmark": True, @@ -68,7 +89,7 @@ def test_pl(): "min_meas": 10, "max_meas": 15, #List number of qubits tested - "list_of_qbits": [4], + "list_of_qbits": [6], } benchmark_arguments.update({"kernel_configuration": kernel_configuration}) @@ -77,8 +98,8 @@ def test_pl(): ae_bench.exe() filename = folder + benchmark_arguments["summary_results"] a = pd.read_csv(filename, header=[0, 1], index_col=[0, 1]) - print(100* list(a['KS']['mean'])[0]) - assert(100* list(a['KS']['mean'])[0] < 1.0) + assert(list(a['KS']['mean'])[0] < 0.1) + assert(list(a['KL']['mean'])[0] < 0.01) shutil.rmtree(folder) test_pl() diff --git a/tnbs/BTC_01_PL/PL/data_loading.py b/tnbs/BTC_01_PL/PL/data_loading.py index 6bfd432..c0708e5 100644 --- a/tnbs/BTC_01_PL/PL/data_loading.py +++ b/tnbs/BTC_01_PL/PL/data_loading.py @@ -293,9 +293,10 @@ def get_theoric_probability(n_qbits: int) -> (np.ndarray, np.ndarray, float, flo data = norma.pdf(x_) data = data/np.sum(data) mindata = np.min(data) - shots = min(1000000, max(10000, round(100/mindata))) + #shots = min(1000000, max(10000, round(100/mindata))) + shots = min(1e7, round(100/mindata)) #data = np.sqrt(data) - return x_, data, mean, sigma, float(step), shots, norma + return x_, data, mean, sigma, float(step), int(shots), norma def get_qlm_probability(data, load_method, shots, qpu): """ diff --git a/tnbs/BTC_01_PL/PL/load_probabilities.py b/tnbs/BTC_01_PL/PL/load_probabilities.py index 3c3b988..b14a0d2 100644 --- a/tnbs/BTC_01_PL/PL/load_probabilities.py +++ b/tnbs/BTC_01_PL/PL/load_probabilities.py @@ -4,9 +4,10 @@ """ import time +import itertools import numpy as np import pandas as pd -from scipy.stats import entropy, chisquare, chi2 +from scipy.stats import entropy, kstest from data_loading import get_theoric_probability, get_qlm_probability class LoadProbabilityDensity: @@ -54,12 +55,12 @@ def __init__(self, **kwargs): #Metric stuff self.ks = None self.kl = None - self.chi2 = None self.fidelity = None - self.pvalue = None self.pdf = None - self.observed_frecuency = None - self.expected_frecuency = None + self.kl_pdf = None + self.samples = None + self.ks_scipy = None + self.ks_pvalue = None def get_quantum_pdf(self): """ @@ -67,6 +68,8 @@ def get_quantum_pdf(self): """ self.result, self.circuit, self.quantum_time = get_qlm_probability( self.data, self.load_method, self.shots, self.qpu) + # For ordering the index using the Int_lsb + self.result.reset_index(inplace=True) def get_theoric_pdf(self): """ @@ -80,37 +83,42 @@ def get_metrics(self): Computing Metrics """ #Kolmogorov-Smirnov + # Transform from state to x value + self.result["x"] = self.x_[self.result["Int_lsb"]] + # Compute cumulative distribution function of the quantum data + self.result["CDF_quantum"] = self.result["Probability"].cumsum() + # Obtain the cumulative distribution function of the + # theoretical Gaussian distribution + self.result["CDF_theorical"] = self.dist.cdf(self.result["x"]) self.ks = np.abs( - self.result["Probability"].cumsum() - self.data.cumsum() - ).max() + self.result["CDF_quantum"] - self.result["CDF_theorical"]).max() + #Kullback-Leibler divergence epsilon = self.data.min() * 1.0e-5 + # Create pandas DF for KL computations + self.kl_pdf = pd.merge( + pd.DataFrame( + [self.x_, self.data], index=["x", "p_th"] + ).T, + self.result[["x", "Probability"]], + on=["x"], how="outer" + ).fillna(epsilon) self.kl = entropy( - self.data, - np.maximum(epsilon, self.result["Probability"]) + self.kl_pdf["p_th"], self.kl_pdf["Probability"] ) - #Fidelity - self.fidelity = self.result["Probability"] @ self.data / \ - (np.linalg.norm(self.result["Probability"]) * \ - np.linalg.norm(self.data)) - - #Chi square - self.observed_frecuency = np.round( - self.result["Probability"] * self.shots, decimals=0) - self.expected_frecuency = np.round( - self.data * self.shots, decimals=0) - try: - self.chi2, self.pvalue = chisquare( - f_obs=self.observed_frecuency, - f_exp=self.expected_frecuency - ) - except ValueError: - self.chi2 = np.sum( - (self.observed_frecuency - self.expected_frecuency) **2 / \ - self.expected_frecuency + + # For testing purpouses + self.samples = list(itertools.chain( + *self.result.apply( + lambda x: [x["x"]] * int(round( + x["Probability"] * self.shots + )), + axis=1 ) - count = len(self.observed_frecuency) - self.pvalue = chi2.sf(self.chi2, count -1) + )) + ks_scipy = kstest(self.samples, self.dist.cdf) + self.ks_scipy = ks_scipy.statistic + self.ks_pvalue = ks_scipy.pvalue def exe(self): """ @@ -140,18 +148,15 @@ def summary(self): self.pdf["shots"] = [self.shots] self.pdf["KS"] = [self.ks] self.pdf["KL"] = [self.kl] - self.pdf["fidelity"] = [self.fidelity] - self.pdf["chi2"] = [self.chi2] - self.pdf["p_value"] = [self.pvalue] self.pdf["elapsed_time"] = [self.elapsed_time] self.pdf["quantum_time"] = [self.quantum_time] if __name__ == "__main__": import argparse - import sys - sys.path.append("../") - from get_qpu import get_qpu + import json + from qpu.benchmark_utils import combination_for_list + from qpu.select_qpu import select_qpu parser = argparse.ArgumentParser() @@ -178,16 +183,66 @@ def summary(self): default="python", help="QPU for simulation: See function get_qpu in get_qpu module", ) + parser.add_argument( + "--count", + dest="count", + default=False, + action="store_true", + help="For counting elements on the list", + ) + parser.add_argument( + "--print", + dest="print", + default=False, + action="store_true", + help="For printing " + ) + parser.add_argument( + "-id", + dest="id", + type=int, + help="For executing only one element of the list", + default=None, + ) + parser.add_argument( + "-json_qpu", + dest="json_qpu", + type=str, + default="qpu/qpu.json", + help="JSON with the qpu configuration", + ) + parser.add_argument( + "--exe", + dest="execution", + default=False, + action="store_true", + help="For executing program", + ) args = parser.parse_args() - print(args) - - - configuration = { - "load_method" : args.method, - "number_of_qbits": args.n_qbits, - "qpu": get_qpu(args.qpu) - } - prob_dens = LoadProbabilityDensity(**configuration) - prob_dens.exe() - print(prob_dens.pdf) - + with open(args.json_qpu) as json_file: + noisy_cfg = json.load(json_file) + final_list = combination_for_list(noisy_cfg) + + + if args.count: + print(len(final_list)) + if args.print: + if args.id is not None: + configuration = { + "load_method" : args.method, + "number_of_qbits": args.n_qbits, + "qpu": final_list[args.id] + } + print(configuration) + else: + print(final_list) + if args.execution: + if args.id is not None: + configuration = { + "load_method" : args.method, + "number_of_qbits": args.n_qbits, + "qpu": select_qpu(final_list[args.id]) + } + prob_dens = LoadProbabilityDensity(**configuration) + prob_dens.exe() + print(prob_dens.pdf) diff --git a/tnbs/BTC_01_PL/PL/notebooks/01_ProbabilityLoadingKernel.ipynb b/tnbs/BTC_01_PL/PL/notebooks/01_ProbabilityLoadingKernel.ipynb index 3c6dbf2..c3cbff5 100644 --- a/tnbs/BTC_01_PL/PL/notebooks/01_ProbabilityLoadingKernel.ipynb +++ b/tnbs/BTC_01_PL/PL/notebooks/01_ProbabilityLoadingKernel.ipynb @@ -23,7 +23,8 @@ "import sys\n", "sys.path.append(\"../\")\n", "import matplotlib.pyplot as plt\n", - "import numpy as np" + "import numpy as np\n", + "import pandas as pd" ] }, { @@ -145,7 +146,7 @@ "metadata": {}, "outputs": [], "source": [ - "x, pn, mu, sigma, deltax, shots, norm = get_theoric_probability(5)\n", + "x, pnx, mu, sigma, deltax, shots, normx = get_theoric_probability(5)\n", "y, pny, muy, sigmay, deltay, shotsy, normy = get_theoric_probability(5)" ] }, @@ -156,7 +157,7 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(x, pn, '-o')\n", + "plt.plot(x, pnx, '-o')\n", "plt.plot(y, pny, '-o')" ] }, @@ -167,7 +168,7 @@ "source": [ "### 2. Creating the probability loading unitary operator $\\mathbf{U}_p$,\n", "\n", - "Once the discrete probability distribution is created the unitary operator $\\mathbf{U}_p$ for loading it into a quantum state should be created. This operator $\\mathbf{U}_p$ acts in the following way:\n", + "Once the discrete probability distribution is obtained, the unitary operator $\\mathbf{U}_p$ for loading it into a quantum state should be created. This operator $\\mathbf{U}_p$ acts in the following way:\n", "\n", "\\begin{equation}\n", " \\mathbf{U}_p|0\\rangle_n = \\sum_{i=0}^{2^n-1} \\sqrt{p_i}|i\\rangle_n\n", @@ -175,7 +176,7 @@ "\n", "The *load_probability* function from **PL/data\\_loading** module creates this operator $\\mathbf{U}_p$ given the discrete probability function as input array. The function needs 2 inputs:\n", "* array with the normalised discrete probability array\n", - "* method: string for selecting the algorithm for creating the $\\mathbf{U}_p$. The algorithm for creating the $\\mathbf{U}_p$ will be the one that appeared in: *Grover, L., & Rudolph, T. (2002). Creating superpositions that correspond to efficiently integrable probability distributions*. In this algorithm, controlled rotations by state are needed to load the probability distribution into the quantum state. The selection method allows different implementations of these controlled rotations by state:\n", + "* method: string for selecting the algorithm for creating the $\\mathbf{U}_p$. The algorithm for creating the $\\mathbf{U}_p$ will be the one that appeared in *Grover, L., & Rudolph, T. (2002). Creating superpositions that correspond to efficiently integrable probability distributions*. In this algorithm, controlled rotations by state are needed to load the probability distribution into the quantum state. The selection method allows different implementations of these controlled rotations by state:\n", " * *brute\\_force*: uses the direct implementation of controlled rotation by state.\n", " * *multiplexor*: the controlled rotations are implemented using **Quantum mulitplexors** as explained in: *V.V. Shende and S.S. Bullock and I.L. Markov. Synthesis of quantum-logic circuits*.\n", " * *KPTree*: **myqlm** implementation of the *Grover and Rudolph* algorithm using **Quantum mulitplexors**.\n", @@ -200,9 +201,9 @@ "metadata": {}, "outputs": [], "source": [ - "Up_BF = load_probability(pn, \"brute_force\")\n", - "Up_QMF = load_probability(pn, \"multiplexor\")\n", - "Up_KPtree = load_probability(pn, \"KPTree\")" + "Up_BF = load_probability(pnx, \"brute_force\")\n", + "Up_QMF = load_probability(pnx, \"multiplexor\")\n", + "Up_KPtree = load_probability(pnx, \"KPTree\")" ] }, { @@ -249,7 +250,7 @@ "This is done by the function *get_qlm_probability* from **data_loading** module. This function executes steps 2 and 3. ´The inputs are:\n", "\n", "* array with the normalised discrete probability array\n", - "* method: string for selecting the algorithm for creating the $\\mathbf{U}_p$. The algorithm for creating the $\\mathbf{U}_p$ will be the one that appeared in *Grover, L., & Rudolph, T. (2002). Creating superpositions that correspond to efficiently integrable probability distributions*. In this algorithm, controlled rotations by state are needed to load the probability distribution into the quantum state. The selection method allows different implementations of these controlled rotations by state:\n", + "* method: string for selecting the algorithm for creating the $\\mathbf{U}_p$. The algorithm for creating the $\\mathbf{U}_p$ will be the one that appeared in *Grover, L., & Rudolph, T. (2002). Creating superpositions that correspond to efficiently integrable probability distributions*. In this algorithm, controlled rotations by state are needed to load the probability distribution into the quantum state. The selection method allows different implementations of these controlled rotations by state:\n", " * *brute\\_force*: uses the direct implementation of controlled rotation by state.\n", " * *multiplexor*: the controlled rotations are implemented using **Quantum mulitplexors** as explained in: *V.V. Shende and S.S. Bullock and I.L. Markov. Synthesis of quantum-logic circuits*.\n", " * *KPTree*: **myqlm** implementation of the *Grover and Rudolph* algorithm using **Quantum mulitplexors**.\n", @@ -257,10 +258,14 @@ "* qpu: **myqlm** quantum process unit (**QPU**) for executing the computation.\n", "\n", "The outputs of the function are:\n", - "* result: pandas DataFrame with the results of the measurements by possible state.\n", + "* result: pandas DataFrame with the results of the measurements by possible state. Columns are:\n", + " * States: the quantum states measured\n", + " * Int_lsb: integer representation of the States using least significative bit\n", + " * Probability: the measured probability of the quantum states: this is $Q_i$\n", + " * Amplitude: amplitude of the quantum states (only for exact simulation).\n", + " * Int: integer representation of the States\n", "* circuit: complete executed circuit in my_qlm format\n", - "* quantum_time: time needed for obtaining the complete quantum distribution.\n", - " " + "* quantum_time: time needed for obtaining the complete quantum distribution." ] }, { @@ -278,31 +283,63 @@ "id": "342530eb-18bc-441c-881c-988848c54e30", "metadata": {}, "source": [ - "First we need to instanciate the **QPU**. We can use the *get_qpu* from **get_qpu** module (in the **BTC_01_PL** folder)" + "First, we need to instantiate the **QPU**. To do this the *select_qpu* from the **qpu.select_qpu** module can be used. This module allows the user to select a **QPU** by providing an input dictionary. \n", + "\n", + "With this *select_qpu* function a qpu for ideal or for a noisy simulation (only when connected to a **EVIDEN Quantum Learning Machine**) can be configured easily.\n", + "\n", + "For more information about how to use the function for noisy simulation, please refer to notebook: **qpu/NoisyModels.ipynb**.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "b29810a2-abe4-4937-b244-08123bdb0c16", + "id": "420abf44", "metadata": {}, "outputs": [], "source": [ - "sys.path.append(\"../../\")\n", - "from get_qpu import get_qpu" + "from qpu.select_qpu import select_qpu" + ] + }, + { + "cell_type": "markdown", + "id": "a5fdc167", + "metadata": {}, + "source": [ + "To configure an ideal simulation the input dictionary should be configured in the following way:" ] }, { "cell_type": "code", "execution_count": null, - "id": "897d2383-8c5d-4539-8d55-6e7c948a0c17", + "id": "d100c974", "metadata": {}, "outputs": [], "source": [ - "qpu_string = \"c\" #python, linalg, mps.\n", - "# For CESGA Users QLM can be used:\n", - "#qpu_string = \"qlmass_linalg\n", - "qpu = get_qpu(qpu_string)" + "qpu_config = {\n", + " #the following strings can be used:\n", + " #c,python, linalg, mps, qlmass_linalg, qlmass_mps\n", + " \"qpu_type\": \"c\", \n", + " # The following keys are used for configuring noisy simulations\n", + " \"t_gate_1qb\" : None,\n", + " \"t_gate_2qbs\" : None,\n", + " \"t_readout\": None,\n", + " \"depol_channel\" : {\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " },\n", + " \"idle\" : {\n", + " \"amplitude_damping\": False,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : None,\n", + " \"t2\" : None\n", + " },\n", + " \"meas\": {\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }\n", + "}\n", + "qpu = select_qpu(qpu_config)" ] }, { @@ -312,7 +349,7 @@ "metadata": {}, "outputs": [], "source": [ - "result, circuit, qtime = get_qlm_probability(pn, \"multiplexor\", shots, qpu)" + "result, circuit, qtime = get_qlm_probability(pnx, \"multiplexor\", shots, qpu)" ] }, { @@ -337,28 +374,197 @@ "%qatdisplay circuit --depth --svg" ] }, + { + "cell_type": "markdown", + "id": "fe1a244c-570d-455a-88f8-5ec5b309b237", + "metadata": {}, + "source": [ + "### 4. Metrics Computation\n", + "\n", + "\n", + "Finally, we need to compare the theoretical probability distribution $N_{\\tilde{\\mu},\\tilde{\\sigma}}(x)$ and the measured quantum ones ($Q$). \n", + "This is done using 2 different metrics:\n", + "\n", + "1. The Kolmogorov-Smirnov (*KS*) distance.\n", + "2. The Kullback-Leibler (*KL*) divergence.\n" + ] + }, + { + "cell_type": "markdown", + "id": "dc3efa2c", + "metadata": {}, + "source": [ + "### 4.1 The Kolmogorov-Smirnov (*KS*) distance.\n", + "\n", + "To compute the **KS** distance following steps should be done:\n", + "\n", + "1. Transform the obtained quantum states to the corresponding $\\ket{i}$ to the original $x_i$ values.\n", + "2. Now for each $x_i$ a probability of $Q_i$ is associated.\n", + "3. Now compute the **KS** distance using:$$KS = \\max_{\\substack{x}} \\left| F^{Q}_n(x) - \\int_{-\\infty}^xN_{\\tilde{\\mu},\\tilde{\\sigma}}(y)dy\\right|$$ where$$F^{Q}_n(x) = \\sum_{i=0}^{2^n-1} \\left\\{\n", + "\\begin{array}{ll}\n", + " Q_i & x_i \\leq x \\\\\n", + " 0 & x_i > x \\\\\n", + "\\end{array}\n", + "\\right.$$" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "6627b195-2c65-479e-be7b-e0de4bc8efbb", + "id": "59647845", "metadata": {}, "outputs": [], "source": [ - "print(\"Time to solution: {}\".format(qtime))" + "#1. Transform the obtained quantum states to the corresponding $\\ket{i}$ to the original $x_i$ values.\n", + "result[\"x\"] = x[result[\"Int_lsb\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5de06bc", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Now we have relation between x_i and Q_i\n", + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8cd18fb", + "metadata": {}, + "outputs": [], + "source": [ + "# Compute KS\n", + "ks = np.abs(\n", + " result[\"Probability\"].cumsum() - normx.cdf(result[\"x\"])\n", + ").max()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7123ee", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "print(\"The Kolmogorov-Smirnov is: {}\".format(ks))" ] }, { "cell_type": "markdown", - "id": "fe1a244c-570d-455a-88f8-5ec5b309b237", + "id": "da0d8e6d", "metadata": {}, "source": [ - "### 4. Metrics Computation\n", + "#### testing KS with scipy package\n", + "\n", + "The proposed **KS** implementation can be compared with the implementation of the **KS** of the scipy package. This package compares the samples from a distribution with a theoretical distribution. We need then the states that were obtained in the quantum routine. We can rebuild them using the information in the *result* pdf:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89803826", + "metadata": {}, + "outputs": [], + "source": [ + "# Re build the quantum sampling\n", + "import itertools\n", + "medidas = list(itertools.chain(\n", + " *result.apply(\n", + " lambda x : [x[\"x\"]] * int(round(x[\"Probability\"] * shots)), \n", + " axis=1\n", + " )\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d413bd9", + "metadata": {}, + "outputs": [], + "source": [ + "#using ks from scipy\n", + "from scipy.stats import entropy, kstest" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33e48c5d", + "metadata": {}, + "outputs": [], + "source": [ + "scipy_ks = kstest(medidas, normx.cdf)\n", + "print(\"KS using scipy: \"+str(scipy_ks.statistic))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6e5c8a3", + "metadata": {}, + "outputs": [], + "source": [ + "# Error between scipy and proposed implementations\n", + "ks - scipy_ks.statistic" + ] + }, + { + "cell_type": "markdown", + "id": "81ca4436", + "metadata": {}, + "source": [ + "### 4.2 The Kullback-Leibler (*KL*) divergence.\n", "\n", - "Finally, we need to compare the theoretical probability distribution ($P_{norm}$) and the quantum ones ($Q$). This is done using 2 different metrics:\n", + "To compute the **KL** divergence the following formula should be used:\n", "\n", - "* The Kolmogorov-Smirnov (*KS*)$$KS = \\max \\left(\\left|\\sum_{j=0}^i P_{norm}(x_j) - \\sum_{j=0}^i Q_j \\right|, \\; \\forall i=0,1,\\cdots, 2^n-1 \\right)$$\n", - "* The Kullback-Leibler divergence (*KL*): $$KL(\\mathbf{Q} / \\mathbf{P_{norm}}) = P_{norm}(x_j) \\ln{\\frac{P_{norm}(x_j)}{\\max(\\epsilon, Q_k)}}$$ where $\\epsilon = \\min(P_{norm}(x_j)) * 10^{-5}$ which guarantees the logarithm exists when $Q_k=0$\n", - " " + "$$KL = \\sum_{i=0}^{2^n-1} P_{norm}(x_i) \\ln \\frac{P_{norm}(x_i)}{\\max(\\epsilon, Q_i)}$$ where $$\\epsilon = \\min(P_{norm}(x_i) *10^{-5})$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb4e506d", + "metadata": {}, + "outputs": [], + "source": [ + "epsilon = pnx.min() * 1.0e-5\n", + "kl_pdf = pd.merge(\n", + " pd.DataFrame(\n", + " [x, pnx], index=[\"x\", \"p_th\"]\n", + " ).T,\n", + " result[[\"x\", \"Probability\"]],\n", + " on = [\"x\"],\n", + " how = \"outer\"\n", + ").fillna(epsilon)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2ed770e", + "metadata": {}, + "outputs": [], + "source": [ + "kl = kl_pdf[\"p_th\"] @ np.log(kl_pdf[\"p_th\"] / kl_pdf[\"Probability\"])\n", + "\n", + "print(\"The Kullback-Leiber divergence is: \"+str(kl))" + ] + }, + { + "cell_type": "markdown", + "id": "8d9f3aeb", + "metadata": {}, + "source": [ + "The entropy function from scipy allows us to compute the **KL**" ] }, { @@ -374,17 +580,30 @@ { "cell_type": "code", "execution_count": null, - "id": "23d85588-ea8b-4889-b465-a204b46f3bcb", + "id": "cda29561", "metadata": {}, "outputs": [], "source": [ - "ks = np.abs(result[\"Probability\"].cumsum() - pn.cumsum()).max()\n", - "epsilon = pn.min() * 1.0e-5\n", - "kl = entropy(pn, np.maximum(epsilon, result[\"Probability\"]))\n", - "\n", - "\n", - "print(\"The Kolmogorov-Smirnov is: {}\".format(ks))\n", - "print(\"The Kullback-Leibler divergence is: {}\".format(kl))" + "sicpy_kl = entropy(kl_pdf[\"p_th\"], kl_pdf[\"Probability\"])\n", + "print(\"The scipy Kullback-Leiber divergence is: \"+str(sicpy_kl))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59ffffa5", + "metadata": {}, + "outputs": [], + "source": [ + "kl - sicpy_kl" + ] + }, + { + "cell_type": "markdown", + "id": "ae57fd4c", + "metadata": {}, + "source": [ + "We can compare graphically the measured quantum distribution versus the theorical discretized one" ] }, { @@ -394,7 +613,7 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(x, pn, '-')\n", + "plt.plot(x, pnx, '-')\n", "plt.plot(x, result[\"Probability\"], 'o')\n", "plt.legend([\"theoretical pdf\", \"quantum pdf\"])" ] @@ -410,7 +629,7 @@ "\n", "* load_method: string with the method for implementing the $\\mathbf{U}_p$\n", "* number_of_qbits: number of qubits for discretizing the domain.\n", - "* qpu: string with the **myqlm QPU** for executing the case." + "* qpu: the QPU for executing the quantum circuits" ] }, { @@ -500,7 +719,9 @@ "cell_type": "code", "execution_count": null, "id": "44d0cab0-3605-402d-8e42-38916a8d5246", - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [], "source": [ "circuit = btc_pl.circuit\n", @@ -546,9 +767,28 @@ "\n", " python load_probabilities.py -h\n", "\n", - "Example: for a 10 qubits circuit using *KPTree* the following command can be used (c lineal algebra library is used).\n", + " usage: load_probabilities.py [-h] [-n_qbits N_QBITS] [-method METHOD] [-qpu QPU] [--count] [--print] [-id ID] [-json_qpu JSON_QPU]\n", + "\n", + " optional arguments:\n", + " -h, --help show this help message and exit\n", + " -n_qbits N_QBITS Number of qbits for interval discretization.\n", + " -method METHOD For selecting the load method: multiplexor, brute_force, KPTree\n", + " -qpu QPU QPU for simulation: See function get_qpu in get_qpu module\n", + " --count For counting elements on the list\n", + " --print For printing\n", + " -id ID For executing only one element of the list\n", + " -json_qpu JSON_QPU JSON with the qpu configuration\n", + "\n", "\n", - " python load_probabilities.py -n_qbits 8 -method KPTree -qpu c" + "The qpu configuration should be provided as json file. In the folder **PL/qpu** two josn samples can be found:\n", + "* *PL/qpu/qpu_ideal.json*: this json configures qpus for ideal simulation.\n", + "* *PL/qpu/qpu_noisy.json*: this json configures qpus for noisy simulation (only valid if user is connected to a EVIDEN QLM)\n", + "\n", + "Example: for a 10 qubits circuit using *KPTree* the following command can be used:\n", + "\n", + " python load_probabilities.py -n_qbits 8 -method KPTree -json qpu/qpu_ideal.json -id 0 --exe\n", + " \n", + "In this case the *CLinalg* myqlm qpu is used (if the qpu/qpu_ideal.json is not modified).\n" ] }, { @@ -590,21 +830,13 @@ "\n", " bash benchmark_exe.sh" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69e12ffb-e0dd-46ab-8b73-777026930673", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python [conda env:tnbs] *", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "conda-env-tnbs-py" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -616,7 +848,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.9.9" } }, "nbformat": 4, diff --git a/tnbs/BTC_01_PL/PL/qpu/NoisyModels.ipynb b/tnbs/BTC_01_PL/PL/qpu/NoisyModels.ipynb new file mode 100644 index 0000000..3423c67 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/NoisyModels.ipynb @@ -0,0 +1,1529 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7612c2a4-9e5e-4c08-8c27-24e761b10478", + "metadata": {}, + "source": [ + "# Noise Model Test Bank (only on QLM)\n", + "\n", + "The module **model_noise** from **QQuantLib.qpu** package allows to create in an easy way noise model for simulation. The following noisy channels can be added to the noisy model in an easy way.\n", + "\n", + "1. Depolarizing channel.\n", + "2. Amplitude Damping.\n", + "3. Dephasing (only if there is Amplitude Damping).\n", + "4. Measurement Channel.\n", + "\n", + "In order to configure a noisy model an input dictionary with the following format should ben provided:\n", + "\n", + "{\n", + "\n", + " 'qpu': \"noisy\",# ideal or noisy\n", + " \n", + " 't_gate_1qb': 35,# ns\n", + " \n", + " 't_gate_2qbs': 660,# ns\n", + " \n", + " 't_readout': 4000, # ns\n", + " \n", + " 'depol_channel': {\n", + " 'active': True, # True or False\n", + " 'error_gate_1qb': 1.0e-4,# float\n", + " 'error_gate_2qbs': 1.0e-3 # float\n", + " },\n", + " \n", + " 'idle': {\n", + " 'amplitude_damping': True, # True or False\n", + " 'dephasing_channel': True, # True or False\n", + " 't1': 0.2e6, #ns\n", + " 't2': 0.1e6 #ns\n", + " },\n", + " \n", + " 'meas': {\n", + " 'active': True, # True or False\n", + " 'readout_error': 1.370e-2# float\n", + " }\n", + "}\n", + "\n", + "The implemented noise modle in **model_noise** module have the following assumptions:\n", + "\n", + "1. The time for 1-qubit gates will be the same for all the possible 1-qubit gates: **t_gate_1qb**. Hardware model set all the 1-qubit gates (used or not) to this value.\n", + "2. The time for 2-qubit gates will be the same for all the possible 2-qubit gates: **t_gate_2qbs**. Hardware model set all the 2-qubit gates (used or not) to this value.\n", + "3. Times for 3-qubits gates (or more) **WON'T BE FIXED**. A rewritter plugin is recomended to use (in the module a toffoli rewritter is added to the final qpu).\n", + "4. Amplitude Damping channels and Dephasing channel should be enabled under the *idle* key of the dictionary:\n", + " * Dephasing channel will be enabled only applied if Amplitude Damping channel was enabled too. This is because $T_1$ and $T_2$ are needed for generating paramented $T_{\\varphi}$ for Dephasing channel.\n", + " * $T_{\\varphi} = \\frac{1}{\\frac{1}{T_2} - \\frac{1}{2 T_1}}$\n", + "6. Depolarizing channel should be enabled and configured under the *depol_channel* key:\n", + " * In the *Depolarizing channel* each time an ideal gate is applied then the depolarizing channel is applied\n", + " * The *Depolarizing channel* will be the same for the 1 and 2 qubit gates.\n", + " * The error asociated to all the 1-qubit gates will be the same: **error_gate_1qb**\n", + " * The error asociated to all the 2-qubit gates will be the same: : **error_gate_2qbs**\n", + "7. Only default gates in Qaptiva **DefaultHardwareModel** can be used. If *hw_model* is a **DefaultHardwareModel** object the default Qaptiva gates can be listed in the following dictionaries:\n", + " * hw_model.gates_specification.quantum_channels: Gates and corresponding definitions. Gates can be of the following type: \n", + " * QuantumChannelKraus. Using *arity* attribute e can know if they are of 1, 2 or more qubits.\n", + " * _ParametricChannel (paramétric gates of 1 qubit)\n", + " * _CtrlParametricChannel (controlled parametric gates: 2 qubits)\n", + " * hw_model.gates_specification.gate_times: dictionary with pair key (gate name) value (execution time of the gate)" + ] + }, + { + "cell_type": "markdown", + "id": "3f4f50c7-cf3f-467c-8ac3-6e2e3d12ada2", + "metadata": {}, + "source": [ + "### Toshiko\n", + "\n", + "T1 = 50 # us\n", + "T2= 30 # us\n", + "F1 = 99.9 # %\n", + "F2 = 92 # %\n", + "F_ro = 90 # %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df1a3ee8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append(\"../../\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd9e1b0b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import qat.lang.AQASM as qlm\n", + "import json\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd3ff415-c947-4c00-b497-02a964ce1b46", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qat.qpus import LinAlg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e44fb05f-b1fa-49d2-a738-80973049fe25", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ideal_qpu = LinAlg()" + ] + }, + { + "cell_type": "markdown", + "id": "97a6ba69-74cf-4638-8883-fa0d5f50b4d1", + "metadata": {}, + "source": [ + "## List of gates" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf7ac396-03bc-46f7-8ac3-b17f2da07d54", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from qat.hardware import DefaultHardwareModel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f0a3029-a74f-4d0b-854e-a2b43948e10e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "hw_md = DefaultHardwareModel()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9dd490a3-6688-4d24-ae5b-0e632bbee898", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Gates and asociated quantum channels\n", + "hw_md.gates_specification.quantum_channels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ff0da3c-2d00-42e4-836c-89360ae9e0e3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# The Kraus operator is the ideal gate\n", + "hw_md.gates_specification.quantum_channels[\"H\"].kraus_operators" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c544156a-8e53-48fb-8b07-9906bd3e8a51", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# time of the gates\n", + "hw_md.gates_specification.gate_times" + ] + }, + { + "cell_type": "markdown", + "id": "8bf3980f", + "metadata": {}, + "source": [ + "## 1. Price Option Problem\n", + "\n", + "We are going to use a price estimation problem for playing with the noise models." + ] + }, + { + "cell_type": "markdown", + "id": "9c0d1868-12d8-4d33-960a-605439b9c3c8", + "metadata": {}, + "source": [ + "### 1. Price Estimation Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e76e75f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from QQuantLib.utils.benchmark_utils import create_pe_problem, combination_for_list, create_ae_pe_solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb71f7eb", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "folder = \"/home/gferro/FinancialApplications/benchmark/q_ae_price/jsons/\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f2042e4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "with open(folder + \"domain_configuration.json\") as json_file:\n", + " domain_cfg = json.load(json_file)\n", + "with open(folder + \"density_probability.json\") as json_file:\n", + " density_cfg = json.load(json_file)\n", + "with open(folder+ \"european_untracked.json\") as json_file:\n", + " payoff_cfg = json.load(json_file)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70230003", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "pe_problem = create_pe_problem(domain_cfg, payoff_cfg, density_cfg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aac9bcd2-39dc-4d31-a8f3-a86ff5cf4740", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "pe_problem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87d1213c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "price_problem = pe_problem[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ac3dec1-6e87-4781-a256-3dbc9b5f5ab8", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "price_problem" + ] + }, + { + "cell_type": "markdown", + "id": "58b12979-ea13-44ab-8d12-707ae1d7c978", + "metadata": {}, + "source": [ + "### 2. Create associated arrays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf512636-c034-47dd-95bb-e2636436805b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from noise_test_bank_functions import create_arrays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fff75a1b-58e5-4c2c-97c1-51e8dbd0ab51", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "domain, norm_pay_off, norm_p_x, pay_off_normalisation, p_x_normalisation = create_arrays(price_problem)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b7006d4-cbc4-4908-96c2-1062ee202a5f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(domain, norm_p_x, '-o')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd62d4ca-e52f-426a-8098-140e8ce5089d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(domain, norm_pay_off, '-o')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1968a832-9441-47f9-a227-b07ea4b8b41e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "integral = np.sum(norm_p_x * norm_pay_off)\n", + "integral" + ] + }, + { + "cell_type": "markdown", + "id": "b1eadc50-0226-4fa4-88f4-68dc299500f8", + "metadata": {}, + "source": [ + "### 3. Load arrays in an Quantum circuit " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54736c01-03cb-4e8a-940d-2ae51c2886ba", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from QQuantLib.DL.encoding_protocols import Encoding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fec08a26-54e7-4e48-a3bb-ec613efdc663", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "encode_class = Encoding(\n", + " array_function=norm_pay_off,\n", + " array_probability=norm_p_x,\n", + " encoding=2\n", + ")\n", + "encode_class.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "282a5d13-8a07-4f8e-831a-ca474e9e544f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "c = encode_class.oracle\n", + "%qatdisplay c" + ] + }, + { + "cell_type": "markdown", + "id": "c2112421-55e1-4293-bd26-592fce05e626", + "metadata": {}, + "source": [ + "### 4. Amplitude Estimation Algorithm\n", + "\n", + "We are going to use a **AE** algorithm." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33cbac17-b9d3-469b-9c56-b4f6273b7a82", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# primero carga la configuración del algoritmo AE\n", + "with open(folder+ \"rqae_configuration_untracked.json\") as json_file:\n", + " ae_cfg = json.load(json_file)\n", + "ae_solver_rqae = combination_for_list(ae_cfg)\n", + "ae_problem = ae_solver_rqae[0]\n", + "ae_problem.update({\"qpu\": ideal_qpu})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b14ca52f-82a5-406d-bc20-0e7a678301cc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ae_problem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5f6b7aa-0bb3-4f53-9038-a10c2b830696", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from QQuantLib.AE.real_quantum_ae import RQAE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee808ef5-3b34-48b0-93f8-a39d9af4f239", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "rqae_object = RQAE(\n", + " oracle=encode_class.oracle,\n", + " target=encode_class.target,\n", + " index=encode_class.index,\n", + " **ae_problem\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "15deb90f-5e23-4c74-9709-f8528a6b9f86", + "metadata": { + "tags": [] + }, + "source": [ + "### 5. First circuit\n", + "\n", + "We are going to use **RQAE**. Some typical **RQAE** parameters are needed. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ed9e561-e9b2-49e8-b4aa-a13b24da6865", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from noise_test_bank_functions import first_step" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9483f21b-1b54-458a-aa2c-377daef9ba1e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "rqae_object.epsilon, rqae_object.ratio, rqae_object.gamma" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7aa70353-6986-4a02-831c-25317e18a659", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "shift, n_i, gamma_i, theoretical_epsilon = first_step(rqae_object.epsilon, rqae_object.ratio, rqae_object.gamma)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c6d19b6-36f6-4e49-8067-8cdccb323bc2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "shift" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b39b1fc-e327-4dd4-85d6-691d7b58d900", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Setting the shift for the first circuit in RQAE\n", + "rqae_object.shifted_oracle = 2.0 * shift\n", + "routine = rqae_object._shifted_oracle" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7779a28-d2ca-4bf4-91d4-1cf569459628", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "%qatdisplay routine" + ] + }, + { + "cell_type": "markdown", + "id": "60bc3bdf", + "metadata": { + "tags": [] + }, + "source": [ + "### 6. Solving the problem Problema\n", + "\n", + "The following code is used for solving first step of RQAE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4484019a-09cf-4aeb-adb6-1891a927a113", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from QQuantLib.utils.data_extracting import get_results\n", + "from QQuantLib.utils.utils import measure_state_probability\n", + "\n", + "def first_step(rutina, qpu, shots, target, shift, gamma, rqae_object):\n", + " \"\"\"\n", + " This function implements the first step of the RQAE paper. The result\n", + " is a first estimation of the desired amplitude.\n", + " \n", + " Parameters\n", + " ----------\n", + " shift : float\n", + " shift for the first iteration\n", + " shots : int\n", + " number of measurements\n", + " gamma : float\n", + " accuracy\n", + " \n", + " Returns\n", + " ----------\n", + " amplitude_min : float\n", + " lower bound for the amplitude to be estimated\n", + " amplitude_max : float\n", + " upper bound for the amplitude to be estimated\n", + " \n", + " \"\"\"\n", + " \n", + " results, circuit, _, _ = get_results(\n", + " rutina, qpu, shots=shots\n", + " )\n", + " \n", + " \n", + " probability_sum = measure_state_probability(\n", + " results, [0] + list(target)\n", + " )\n", + " \n", + " #probability_diff = results[\"Probability\"].iloc[\n", + " # bitfield_to_int([1] + list(self.target))\n", + " #]\n", + " probability_diff = measure_state_probability(\n", + " results, [1] + list(target)\n", + " )\n", + " \n", + " return (probability_sum - probability_diff) / (4 * shift)\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "89406be8-c081-46b3-aee7-4cb067713eeb", + "metadata": {}, + "source": [ + "## 7. Ideal Solution\n", + "\n", + "In order to get the ideal solution we need to instantiate a ideal qpu. For loading a ideal qpu we can use the typical **get_qpu** from **QQuantLib.qpu** package. In order to have a better integration between ideal QPUs and noisy QPUs a wrapper function called *select_qpu* inside of the **QQuantLib.qpu.select_qpu** module was implemented. \n", + "\n", + "The input of the *select_qpu* function is a dictionary like the used for configuring a noise model:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "590614bf-994c-41c7-8ca9-115038de0cef", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from QQuantLib.qpu.select_qpu import select_qpu" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fce1c0b-3369-4981-81b4-59caec0d42f2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "qpus = [\"c\", \"python\", \"linalg\", \"mps\", \"qlmass_linalg\", \"qlmass_mps\"]\n", + "conf_ideal = [{\n", + " \"qpu_type\": [qpus[2]],\n", + " \"t_gate_1qb\" : [None],\n", + " \"t_gate_2qbs\" : [None],\n", + " \"t_readout\": [None],\n", + " \"depol_channel\" : [{\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " }],\n", + " \"idle\" : [{\n", + " \"amplitude_damping\": False,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : None,\n", + " \"t2\" : None\n", + " }],\n", + " \"meas\": [{\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }]\n", + "}]\n", + "\n", + "# We use the combination_for_list for getting the proper format for the dictionary\n", + "ideal_qpu_conf = combination_for_list(conf_ideal)[0]\n", + "print(ideal_qpu_conf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e3ab16e-c5a6-4cd5-8112-b62db34561b1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ideal_qpu = select_qpu(ideal_qpu_conf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fa48787-6dce-4cf4-a366-62c802a5c9ac", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Ideal Solution\n", + "ideal_meas = first_step(routine, ideal_qpu, 0, rqae_object.target, shift, gamma_i, rqae_object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbaac171-a8d3-4799-ac66-cdd1a1d8378a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ideal_meas" + ] + }, + { + "cell_type": "markdown", + "id": "0d6b09c7-3f49-42f0-a9ee-d75ff81b7a1a", + "metadata": {}, + "source": [ + "## 8. Solution with Noisy hardware\n", + "\n", + "For simulating the noisy hardware we need to configure the noisy hardware model and create a noisy QPU. This can be done with the *create_qpu* from **QQuantLib.qpu.model_noise**. However we recommend to use the wrapper function *select_qpu* from **QQuantLib.qpu.select_qpu** module " + ] + }, + { + "cell_type": "markdown", + "id": "27f44a1d-74d4-451c-aed4-cc48b9e1bffd", + "metadata": {}, + "source": [ + "### 8.1 No Noise and Toffoli rewritter\n", + "\n", + "We can use an ideal qpu but ask for a rewritting of toffolis to 1 and 2 qubits gates. This can be by configuring the noise dictionary in the following way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b0425ee-21e5-4254-a014-362b7f22fc33", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ideal_toffoli_rewritter = [{\n", + " \"qpu_type\": [\"ideal\"],\n", + " \"t_gate_1qb\" : [None],\n", + " \"t_gate_2qbs\" : [None],\n", + " \"t_readout\": [None],\n", + " \"depol_channel\" : [{\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " }],\n", + " \"idle\" : [{\n", + " \"amplitude_damping\": False,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : None,\n", + " \"t2\" : None\n", + " }],\n", + " \"meas\": [{\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }]\n", + "}]\n", + "conf_ideal_no_toffoli = combination_for_list(ideal_toffoli_rewritter)[0]\n", + "conf_ideal_no_toffoli" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79f439dc-951f-496e-a44d-ddfd055b0aaf", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "ideal_qpu_toffoli_rew = select_qpu(conf_ideal_no_toffoli)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fb8b186-beb9-40df-84e5-33bc6651f705", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Original Circuit has Toffolis\n", + "%qatdisplay routine --depth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e633d778-383e-4f88-a1e6-ac114e176167", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Compile circuit for rewrite toffolis\n", + "from qat.core import Job, Batch\n", + "batch = Batch(jobs=[routine.to_circ().to_job()])\n", + "new_circ = ideal_qpu_toffoli_rew.compile(batch).jobs[0].circuit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21623c0e-487f-4656-bb35-1dfd9deaa675", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# New circuit has not Toffolis\n", + "%qatdisplay new_circ --svg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c5554fe-b4cb-4b47-b023-515d6c995f2a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# deal soltuion. No Toffoli circuit\n", + "ideal_no_toffoli_meas = first_step(routine, ideal_qpu_toffoli_rew, 0, rqae_object.target, shift, gamma_i, rqae_object)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "934dcc88-611a-4fb5-b627-2e83a02dfa51", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#Shoud be simmilar\n", + "ideal_no_toffoli_meas, ideal_meas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aeff7dc0-24cd-4e40-8d4e-097fba17d919", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "np.abs(ideal_no_toffoli_meas-ideal_meas)" + ] + }, + { + "cell_type": "markdown", + "id": "8e193c8c-bff8-4dcc-8276-28e38a817027", + "metadata": { + "tags": [] + }, + "source": [ + "### 8.2 Depolarizing channel" + ] + }, + { + "cell_type": "markdown", + "id": "2961c7cd-5500-45b5-82d2-f22716506b6c", + "metadata": { + "tags": [] + }, + "source": [ + "### Toshiko\n", + "\n", + "T1 = 50 # us\n", + "T2= 30 # us\n", + "F1 = 99.9 # %\n", + "F2 = 92 # %\n", + "F_ro = 90 # %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99a831f2-bbc6-4182-a2f0-0afd7ca59a54", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Configuring test for Deploarizing channel\n", + "conf_noise = [{\n", + " \"qpu_type\": [\"noisy\"],\n", + " \"t_gate_1qb\" : [35],\n", + " \"t_gate_2qbs\" : [660],\n", + " \"t_readout\": [0],\n", + " \"depol_channel\" : [\n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 1.0e-9,\n", + " \"error_gate_2qbs\" : 1.0e-8\n", + " },\n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 1.0e-8,\n", + " \"error_gate_2qbs\" : 1.0e-7\n", + " }, \n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 1.0e-7,\n", + " \"error_gate_2qbs\" : 1.0e-6\n", + " }, \n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 1.0e-6,\n", + " \"error_gate_2qbs\" : 1.0e-5\n", + " }, \n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 1.0e-5,\n", + " \"error_gate_2qbs\" : 1.0e-4\n", + " }, \n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 2.27e-4, # brisbane\n", + " \"error_gate_2qbs\" : 7.741e-3 # brisbane\n", + " }, \n", + " {\n", + " \"active\": True,\n", + " \"error_gate_1qb\" : 0.001, # Toshiko\n", + " \"error_gate_2qbs\" : 0.08 # Toshiko\n", + " }, \n", + " ],\n", + " \"idle\" : [{\n", + " \"amplitude_damping\": False,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : None,\n", + " \"t2\" : None\n", + " }],\n", + " \"meas\": [{\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }]\n", + "}]\n", + "# Now we have a list with different dictionaries\n", + "noisy_conf_list = combination_for_list(conf_noise)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb06c24d-d5af-45e2-8cb8-bef0cd3ecdd1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Now we are going to solve the circuit with all the different depolarising channel configurations\n", + "a_depol = []\n", + "\n", + "error1 = []\n", + "for hw_m in noisy_conf_list:\n", + " my_noisy_qpu = select_qpu(hw_m)\n", + " print(hw_m)\n", + " error1.append(hw_m[\"depol_channel\"][\"error_gate_1qb\"])\n", + " step = first_step(routine, my_noisy_qpu, 0, rqae_object.target, shift, gamma_i, rqae_object)\n", + " a_depol.append(step)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "076a85f2-b44f-42bc-8aa6-7ea311797d21", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, np.abs(a_depol - ideal_no_toffoli_meas), '-o')\n", + "#plt.axhline(medida_no_toffoli, c='r')\n", + "plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"Error 1 qubit gate\")\n", + "plt.ylabel(r\"$\\hat{a}-a_{ideal}$\")\n", + "plt.title(\"k=0. Only depolarizing channel. No iddle qubit\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81227266-0c70-47c3-ba07-14202946a850", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, a_depol, '-o')\n", + "plt.axhline(ideal_no_toffoli_meas, c='r')\n", + "#plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"Error 1 qubit gate\")\n", + "plt.ylabel(r\"$\\hat{a}$\")\n", + "plt.title(\"k=0. Only depolarizing channel. No iddle qubit\")" + ] + }, + { + "cell_type": "markdown", + "id": "454696a9-f71d-4538-8657-b314d81ebd98", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "tags": [] + }, + "source": [ + "### 8.3 Amplitude Damping Channel (No Dephasing)" + ] + }, + { + "cell_type": "markdown", + "id": "a23ba314-384a-4a34-b275-980eeef96edc", + "metadata": { + "tags": [] + }, + "source": [ + "### Toshiko\n", + "\n", + "T1 = 50 # us\n", + "T2= 30 # us\n", + "F1 = 99.9 # %\n", + "F2 = 92 # %\n", + "F_ro = 90 # %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf63f1dd-64a8-4dc5-884e-139d8da60d19", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "conf_noise = [{\n", + " \"qpu_type\": [\"noisy\"],\n", + " \"t_gate_1qb\" : [35],\n", + " \"t_gate_2qbs\" : [660],\n", + " \"t_readout\": [0],\n", + " \"depol_channel\" : [\n", + " {\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " } \n", + " ],\n", + " \"idle\" : [\n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 1000e6,\n", + " \"t2\" : None\n", + " },\n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 100e6,\n", + " \"t2\" : None\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 10e6,\n", + " \"t2\" : None\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 1e6,\n", + " \"t2\" : None\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 0.231e6, # brisbane\n", + " \"t2\" : None \n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : 50e3, # Toshiko: 50 us\n", + " \"t2\" : None \n", + " } \n", + " ],\n", + " \"meas\": [{\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }]\n", + "}]\n", + "noisy_conf_list = combination_for_list(conf_noise)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2979c3a6-65a0-4960-8b85-83322e9284e0", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "a_ad = []\n", + "\n", + "error1 = []\n", + "for hw_m in noisy_conf_list:\n", + " my_noisy_qpu = select_qpu(hw_m)\n", + " print(hw_m)\n", + " error1.append(hw_m[\"idle\"][\"t1\"])\n", + " step = first_step(routine, my_noisy_qpu, 0, rqae_object.target, shift, gamma_i, rqae_object)\n", + " a_ad.append(step)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d89c25d7-1871-43c6-8973-5235c3c62fab", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "plt.plot(error1, ideal_no_toffoli_meas - a_ad, '-o')\n", + "#plt.axhline(medida_no_toffoli, c='r')\n", + "#plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"T1 (ns)\")\n", + "plt.ylabel(r\"$\\hat{a}-a_{ideal}$\")\n", + "plt.title(\"k=0. Only Amplitude Damping. Ideal Gates\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e257a2da-c2c0-472b-b18a-c9089e9d2ef8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, a_ad, '-o')\n", + "plt.axhline(ideal_no_toffoli_meas, c='r')\n", + "#plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"T1 (ns)\")\n", + "plt.ylabel(r\"$\\hat{a}$\")\n", + "plt.title(\"k=0. Only depolarizing channel. No iddle qubit\")" + ] + }, + { + "cell_type": "markdown", + "id": "a11ee806-27d9-4cd9-bf8e-668f6320b014", + "metadata": {}, + "source": [ + "### 8.4 Amplitude Damping and Dephasing Channels" + ] + }, + { + "cell_type": "markdown", + "id": "80d46c0e-771b-4d7a-9fba-09175c4fc204", + "metadata": { + "tags": [] + }, + "source": [ + "### Toshiko\n", + "\n", + "T1 = 50 # us\n", + "T2= 30 # us\n", + "F1 = 99.9 # %\n", + "F2 = 92 # %\n", + "F_ro = 90 # %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8100dd84-bd6b-47b0-91fc-dd682fee3e41", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "conf_noise = [{\n", + " \"qpu_type\": [\"noisy\"],# Palabara para generar qpus ruidosas\n", + " \"t_gate_1qb\" : [35],\n", + " \"t_gate_2qbs\" : [660],\n", + " \"t_readout\": [0],\n", + " \"depol_channel\" : [\n", + " {\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " } \n", + " ],\n", + " \"idle\" : [\n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 1000e6,\n", + " \"t2\" : 500e6\n", + " },\n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 100e6,\n", + " \"t2\" : 50e6\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 10e6,\n", + " \"t2\" : 5e6\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 1e6,\n", + " \"t2\" : 0.5e6\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 0.231e6, # brisbane\n", + " \"t2\" : 0.132e6 # brisbane\n", + " }, \n", + " {\n", + " \"amplitude_damping\": True,\n", + " \"dephasing_channel\": True,\n", + " \"t1\" : 50e3, # Toshiko: 50 us\n", + " \"t2\" : 30e3 # Toshiko: 30 us\n", + " }, \n", + " ],\n", + " \"meas\": [{\n", + " \"active\":False,\n", + " \"readout_error\": None\n", + " }]\n", + "}]\n", + "noisy_conf_list = combination_for_list(conf_noise)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "323612f8-466b-4779-a646-2f847b4bc76a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "a_ad_d = []\n", + "\n", + "error1 = []\n", + "for hw_m in noisy_conf_list:\n", + " my_noisy_qpu = select_qpu(hw_m)\n", + " print(hw_m)\n", + " error1.append(hw_m[\"idle\"][\"t1\"])\n", + " step = first_step(routine, my_noisy_qpu, 0, rqae_object.target, shift, gamma_i, rqae_object)\n", + " a_ad_d.append(step)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "730e9c40-9819-4939-b6a1-13c4bdb14d72", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, np.abs(a_ad_d - ideal_no_toffoli_meas), '-o')\n", + "#plt.axhline(medida_no_toffoli, c='r')\n", + "plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"T1 (ns)\")\n", + "plt.ylabel(r\"$\\hat{a}-a_{ideal}$\")\n", + "plt.title(\"k=0. Amplitude Damping and Dephasing. Ideal Gates\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5625c9d1-0409-4508-8e8f-a0e1e8ea0d5f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, a_ad_d, '-o')\n", + "plt.axhline(ideal_no_toffoli_meas, c='r')\n", + "plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"T1 (ns)\")\n", + "plt.ylabel(r\"$\\hat{a}$\")\n", + "plt.title(\"k=0. Amplitude Damping and Dephasing. Ideal Gates\")" + ] + }, + { + "attachments": { + "2bd71b2c-9576-4106-a83c-ba16680fcf30.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "65550258-558d-4eff-a4b8-911f058e9599", + "metadata": {}, + "source": [ + "![image.png](attachment:2bd71b2c-9576-4106-a83c-ba16680fcf30.png)" + ] + }, + { + "cell_type": "markdown", + "id": "849971a3-1a1c-4cab-9098-bfe03524a10b", + "metadata": {}, + "source": [ + "### 8.5 Redout error" + ] + }, + { + "cell_type": "markdown", + "id": "421b48d3-a4cd-4b8f-83bb-92d60bc3b120", + "metadata": { + "tags": [] + }, + "source": [ + "### Toshiko\n", + "\n", + "T1 = 50 # us\n", + "T2= 30 # us\n", + "F1 = 99.9 # %\n", + "F2 = 92 # %\n", + "F_ro = 90 # %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2594a2fe-d13d-4a17-867d-c70944d8ff36", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "conf_noise = [{\n", + " \"qpu_type\": [\"noisy\"],\n", + " \"t_gate_1qb\" : [35],\n", + " \"t_gate_2qbs\" : [660],\n", + " \"t_readout\": [0],\n", + " \"depol_channel\" : [\n", + " {\n", + " \"active\": False,\n", + " \"error_gate_1qb\" : None,\n", + " \"error_gate_2qbs\" : None\n", + " } \n", + " ],\n", + " \"idle\" : [\n", + " {\n", + " \"amplitude_damping\": False,\n", + " \"dephasing_channel\": False,\n", + " \"t1\" : None,\n", + " \"t2\" : None\n", + " } \n", + " ],\n", + " \"meas\": [\n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 1e-6\n", + " },\n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 1e-5\n", + " },\n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 1e-4\n", + " }, \n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 1e-3\n", + " }, \n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 1.300e-2 # brisbane\n", + " },\n", + " {\n", + " \"active\":True,\n", + " \"readout_error\": 0.1 #Toshiko\n", + " } \n", + " ]\n", + "}]\n", + "noisy_conf_list = combination_for_list(conf_noise)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9207b9c8-4f92-4eb3-8383-833c9c87d839", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "a_read = []\n", + "\n", + "error1 = []\n", + "for hw_m in noisy_conf_list:\n", + " my_noisy_qpu = select_qpu(hw_m)\n", + " print(hw_m)\n", + " error1.append(hw_m[\"meas\"][\"readout_error\"])\n", + " step = first_step(routine, my_noisy_qpu, 0, rqae_object.target, shift, gamma_i, rqae_object)\n", + " a_read.append(step)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c7e5e23-a03b-49b2-bf91-bc83f41cca54", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, np.abs(a_read - ideal_no_toffoli_meas), '-o')\n", + "#plt.axhline(medida_no_toffoli, c='r')\n", + "plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"Readout Error\")\n", + "plt.ylabel(r\"$\\hat{a}-a_{ideal}$\")\n", + "plt.title(\"k=0. Only Readout Error.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3edd547-1dde-4880-8097-b348fe8b2b12", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plt.plot(error1, a_read, '-o')\n", + "plt.axhline(ideal_no_toffoli_meas, c='r')\n", + "#plt.yscale(\"log\")\n", + "plt.xscale(\"log\")\n", + "plt.xlabel(\"Readout Error\")\n", + "plt.ylabel(r\"$\\hat{a}$\")\n", + "plt.title(\"k=0. Only Readout Error.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ddc2ca3-a5fc-4fb6-a93f-8a59f64f0976", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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/tnbs/BTC_01_PL/PL/qpu/REAME.md b/tnbs/BTC_01_PL/PL/qpu/REAME.md new file mode 100644 index 0000000..8a7665c --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/REAME.md @@ -0,0 +1,3 @@ +# Noisy Models + +At the momement the noisy models from model_noise can be only used in a QLM. diff --git a/tnbs/BTC_01_PL/PL/qpu/__init__.py b/tnbs/BTC_01_PL/PL/qpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tnbs/BTC_01_PL/PL/qpu/benchmark_utils.py b/tnbs/BTC_01_PL/PL/qpu/benchmark_utils.py new file mode 100644 index 0000000..5dce5b0 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/benchmark_utils.py @@ -0,0 +1,138 @@ +""" +Utils functions from benchmark purpouses. + +Authors: Alberto Pedro Manzano Herrero & Gonzalo Ferro +""" +import json +import itertools as it +from collections import ChainMap + +def combination_for_dictionary(input_dict): + """ + Creates a list of dictionaries with all the posible combination of + the input dictionary. + + Parameters + ---------- + input_dict : python dictionary + python dictionary where each key value MUST be a list. For each + value of a list a new dictioanry will be created + + Returns + ---------- + list_of_dictionaries : list of python dictionaries + A list with all posible combination of dictionaries from the + input dictionary + """ + + list_of_dictionaries = [ + dict(zip(input_dict, x)) for x in it.product(*input_dict.values()) + ] + return list_of_dictionaries + + +def combination_for_list(input_list): + """ + For each dictionary of the list the function creates all posible + combinations. All the posible combinations are concatenated. + + Parameters + ---------- + input_list : list of python dictionary + The values of each key of the each python dictionary MUST BE lists. + + Returns + ---------- + list_of_combinations : list of python dictionaries + A list with the concatenation of all posible combinations for + each dictionary of the input_list + """ + list_of_combinations = [] + for step_dict in input_list: + list_of_combinations = list_of_combinations + combination_for_dictionary( + step_dict + ) + return list_of_combinations + +def create_pe_problem(domain_cfg, payoff_cfg, density_cfg): + """ + Create a list of price estimation problems. Each element is a python + dictionary with a complete option price estimation problem. + + Parameters + ---------- + domain_cfg : list of dictionaries + Each dictionary has a domain configuration for a price estimation problem. + payoffs_cfg : list of dictionaries + Each dictionary has an option configuration for a price estimation problem. + density_cfg : list of dictionaries + Each dictionary has probability density configuration for a price estimation problem. + + Returns + ---------- + pe_problem_list : list of dictionaries + list with different price estimation problems. + """ + + # List of density probabilities dictionaries + dp_list = combination_for_list(density_cfg) + # List for pay offs + po_list = combination_for_list(payoff_cfg) + # list of domain dictionaries + do_list = combination_for_list(domain_cfg) + pe_problem_list = [ + dict(ChainMap(*list(x))) for x in it.product(dp_list, do_list, po_list) + ] + return pe_problem_list + +def create_ae_pe_solution(ae_list, problem_list): + """ + Creates a list of price estimation problems for solving with amplitude + estimation (AE) techniques. Each element will have the complete + information for generating a price estimation problem and the + configuration for solving it using an AE algorithm. This is each element + is a python dictionary that allows define a price estimation problem + and solving it using a properly configure AE algorithm + + Parameters + ---------- + ae_list : list + List with properly configured AE solvers. + problem_list : list + List with different price estimation problems. + + Returns + ---------- + solve_ae_pe_list : list + List where each element is a ae_pricep dictionary + The list will have the combination of each posible amplitude + estimation solver with all posible price problem list + """ + solve_ae_pe_list = [] + for ae in ae_list: + step_list = [dict(ChainMap(*list(x))) for x in it.product(problem_list, [ae])] + solve_ae_pe_list = solve_ae_pe_list + step_list + return solve_ae_pe_list + +def list_of_dicts_from_jsons(ae_json_list): + """ + Creates a list of dictionaries from inputs jsons. + + Parameters + ---------- + ae_list : list of json. + List with name of json files with a complete configuration of an + amplitude estimation method + + Returns + ---------- + ae_pricep_list : list of python dictionaries + """ + ae_list = [] + for ae_json in ae_json_list: + with open(ae_json) as json_file: + ae_list = ae_list + json.load(json_file) + ae_list = combination_for_list(ae_list) + return ae_list + #ae_pricep_list = create_ae_pricep_list(ae_list, problem_list) + #return ae_pricep_list diff --git a/tnbs/BTC_01_PL/PL/qpu/get_qpu.py b/tnbs/BTC_01_PL/PL/qpu/get_qpu.py new file mode 100644 index 0000000..2594f11 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/get_qpu.py @@ -0,0 +1,84 @@ +""" +This module implements the get_qpu function that allows to the user +select a **EVIDEN QPU** for ideal simulation. The qpu variable is a +string that should take some of the following values: + + + **qlmass_linalg**. + For selecting the linear algebra simulator LinAlg. This QPU + can be used only with QaptivaÔäó Appliance when the user sends the computations to a remote QPU. The user must have remote + access to a remote QLM using the Qaptiva Access (QLM as a Service) + library. + **qlmass_mps**. + For selecting the Matrix Product State (MPS) simulator. This QPU + can be used only with QaptivaÔäó Appliance when the user sends the computations to a remote QPU. The user must have remote + access to a remote QLM using the Qaptiva Access (QLM as a Service) + library. + **python**. + For selecting the linear algebra simulator PyLinalg. This a pure + Python algebra simulator. This QPU is provided by the myQLM + library. It can not be used with QaptivaÔäó Appliance. + **c** + For selecting the linear algebra simulator CLinalg. This a pure + C algebra simulator. This QPU is provided by the myQLM + library. It can not be used with QaptivaÔäó Appliance. + **linalg** + For selecting the linear algebra simulator LinAlg. This QPU + can be used only with QaptivaÔäó Appliance when the user is locally + in a QLM. + **mps** + For selecting the Matrix Product State (MPS) simulator This QPU + can be used only with QaptivaÔäó Appliance when the user is locally + in a QLM. +""" + +def get_qpu(qpu=None): + """ + Function for selecting solver. + + Parameters + ---------- + + qpu : str + string with the desired qpu + + Returns + ---------- + + linal_qpu : solver for quantum jobs + """ + + if qpu is None: + raise ValueError( + "qpu CAN NOT BE NONE. Please select one of the three" + + " following options: qlmass, python, c") + if qpu == "qlmass_linalg": + try: + from qlmaas.qpus import LinAlg + linalg_qpu = LinAlg() + except (ImportError, OSError) as exception: + raise ImportError( + "Problem Using QLMaaS. Please create config file" + + "or use mylm solver") from exception + elif qpu == "qlmass_mps": + try: + from qlmaas.qpus import MPS + #linalg_qpu = MPS(lnnize=True) + linalg_qpu = MPS() + except (ImportError, OSError) as exception: + raise ImportError( + "Problem Using QLMaaS. Please create config file" + + "or use mylm solver") from exception + elif qpu == "python": + from qat.qpus import PyLinalg + linalg_qpu = PyLinalg() + elif qpu == "c": + from qat.qpus import CLinalg + linalg_qpu = CLinalg() + elif qpu == "linalg": + from qat.qpus import LinAlg + linalg_qpu = LinAlg() + elif qpu == "mps": + from qat.qpus import MPS + linalg_qpu = MPS() + return linalg_qpu diff --git a/tnbs/BTC_01_PL/PL/qpu/model_noise.py b/tnbs/BTC_01_PL/PL/qpu/model_noise.py new file mode 100644 index 0000000..b2258b2 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/model_noise.py @@ -0,0 +1,169 @@ +""" +This module implements several functions for configuring a noisy +hardware model for creating the corresponding noisy qpu. +**BE AWARE** +The functions of this module can be only used with the Qaptiva™ Appliance +and when the user is locally in a QLM. The Qaptiva Access library **CAN +NOT BE** used with these functions. +""" + +import numpy as np + +# Obtenido de ibm_brisbane: 2024/04/04 +# error_gate_1qb = 2.27e-4 +# error_gate_2qbs = 7.741e-3 +# t_gate_1qb = 35 #ns +# t_gate_2qbs = 660 #ns +# t1 = 231.94e3 +# t2 = 132.71e3 + +def set_gate_times(t_gate_1qb=35, t_gate_2qbs=660, t_readout=4000): + """ + Set the gate times for a noise model. + + Parameters + ---------- + + t_gate_1qb : int + time for 1 qubit gate length in ns + t_gate_2qbs : int + time for 2 qubits gate length in ns + t_readout : int + time for readout gate in ns + + Return + ------ + + gate_time_dict : dict + dictionary with the default gates and their time length + + """ + from qat.hardware import DefaultHardwareModel + from qat.hardware.default import _CtrlParametricChannel, _ParametricChannel + from qat.quops.quantum_channels import QuantumChannelKraus + hw_m = DefaultHardwareModel() + gate_time_dict = {} + for gate, value in hw_m.gates_specification.quantum_channels.items(): + if gate not in ["measure", "reset", "logic"]: + if isinstance(value, _CtrlParametricChannel): + gate_time_dict.update({gate: lambda angle: t_gate_2qbs}) + if isinstance(value, _ParametricChannel): + gate_time_dict.update({gate: lambda angle: t_gate_1qb}) + if isinstance(value, QuantumChannelKraus): + if value.arity == 1: + gate_time_dict.update({gate: t_gate_1qb}) + if value.arity == 2: + gate_time_dict.update({gate: t_gate_2qbs}) + else: + if gate == "measure": + gate_time_dict.update({gate: t_readout}) + return gate_time_dict + +def noisy_hw_model(hw_cfg): + """ + My noisy hardware model: It is composed by 3 types of noise channels: + Amplitude Damping and Dephasing channels for idle qubits + Depolarizing channel applied after any gate. + + Parameters + ---------- + + hw_cfg : dict + Python dictionary with parameters for the noisy hardware: + * error_gate_1qb : Error for 1-qubit gate (for Depolarizing channel) + * error_gate_2qbs: Error for 2-qubits gates (for Depolarizing channel) + * t_gate_1qb : duration time in nanoseconds for 1 qubit gates + * t_gate_2qbs : duration time in nanoseconds for 2 qubit gates + * t1 : T1 time in nanoseconds (Amplitude Damping and Dephasing channels) + * t2 : T2 time in nanoseconds (Dephasing channel) + + Return + ------ + + my_hw_model : Qaptiva HardwareModel + my HardwareModel definition + """ + t_gate_1qb = hw_cfg.get("t_gate_1qb", 35) + t_gate_2qbs = hw_cfg.get("t_gate_2qbs", 660) + t_readout = hw_cfg.get("t_readout", 4000) + #Gates Specification + gate_time_dict = set_gate_times(t_gate_1qb, t_gate_2qbs, t_readout) + depol_channel = hw_cfg.get("depol_channel") + if depol_channel["active"]: + from qat.hardware import make_depolarizing_hardware_model + # Hardware model for depolarizing channel + error_gate_1qb = depol_channel.get("error_gate_1qb", 2.27e-4) + error_gate_2qbs = depol_channel.get("error_gate_2qbs", 7.741e-3) + my_hw_model = make_depolarizing_hardware_model( + eps1=error_gate_1qb, eps2=error_gate_2qbs + ) + else: + from qat.hardware import DefaultHardwareModel + my_hw_model = DefaultHardwareModel() + # Setting time for the gates + my_hw_model.gates_specification.gate_times.update(gate_time_dict) + idle = hw_cfg.get("idle") + idle_noise_list = [] + if idle["amplitude_damping"]: + from qat.quops import ParametricAmplitudeDamping + # Setting AmplitudeDamping iddle channel + t1 = idle.get("t1", 231.94e3) + idle_noise_list.append(ParametricAmplitudeDamping(T_1=t1)) + if idle["dephasing_channel"]: + from qat.quops import ParametricPureDephasing + # Setting Dephasing iddle channel + t2 = idle.get("t2", 132.71e3) + tphi = 1/(1/t2 - 1/(2 * t1)) + idle_noise_list.append(ParametricPureDephasing(T_phi=tphi)) + # Setting idle channels + my_hw_model.idle_noise = idle_noise_list + meas = hw_cfg.get("meas") + if meas["active"]: + # Setting Measurement noise channel + readout_error = meas["readout_error"] + meas_prep = np.array([[readout_error, 0.0],[0.0, 1.0-readout_error]]) + my_hw_model.gates_specification.meas = meas_prep + return my_hw_model + +def create_qpu(hw_cfg): + """ + Create QPU. Using an input hardware configuration this function creates + a QPU. It could be a noisy or a ideal qpu depending on the value of the key + qpu of the hw_cfg dictionary. Additionally adds a plugin for rewiting the + Toffolis using CNOTS and local gates. + + Parameters + ---------- + + hw_cfg : dict + Python dictionary with parameters for configuring the QPU + * qpu : If noisy the function creates a Noisy QPU. Else create the corresponding ideal QPU. + * error_gate_1qb : Error for 1-qubit gate (for Depolarizing channel) + * error_gate_2qbs: Error for 2-qubits gates (for Depolarizing channel) + * t_gate_1qb : duration time in nanoseconds for 1 qubit gates + * t_gate_2qbs : duration time in nanoseconds for 2 qubit gates + * t1 : T1 time in nanoseconds (Amplitude Damping and Dephasing channels) + * t2 : T2 time in nanoseconds (Dephasing channel) + Return + ------ + + my_qpu : Qaptiva QPU + generated QPU (can be a noisy one) + """ + + from qat.synthopline.compiler import EXPANSION_COLLECTION + from qat.pbo import PatternManager + from qat.qpus import NoisyQProc, LinAlg + # Rewritter for Toffolis + toffoli_plugin = PatternManager(collections=[EXPANSION_COLLECTION[:1]]) + if hw_cfg["qpu_type"] == "noisy": + model_noisy = noisy_hw_model(hw_cfg) + my_qpu= NoisyQProc( + hardware_model=model_noisy, + sim_method="deterministic-vectorized", + backend_simulator=LinAlg() + ) + else: + my_qpu = LinAlg() + my_qpu = toffoli_plugin | toffoli_plugin | my_qpu + return my_qpu diff --git a/tnbs/BTC_01_PL/PL/qpu/qpu_ideal.json b/tnbs/BTC_01_PL/PL/qpu/qpu_ideal.json new file mode 100644 index 0000000..98aad11 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/qpu_ideal.json @@ -0,0 +1,24 @@ + +[ + { + "qpu_type": ["c", "python", "linalg", "mps", "qlmass_linalg", "qlmass_mps"], + "t_gate_1qb" : [null], + "t_gate_2qbs" : [null], + "t_readout": [null], + "depol_channel" : [{ + "active": false, + "error_gate_1qb" : null, + "error_gate_2qbs" : null + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": false, + "t1" : null, + "t2" : null + }], + "meas": [{ + "active":false, + "readout_error": null + }] + } +] diff --git a/tnbs/BTC_01_PL/PL/qpu/qpu_noisy.json b/tnbs/BTC_01_PL/PL/qpu/qpu_noisy.json new file mode 100644 index 0000000..9b3f7df --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/qpu_noisy.json @@ -0,0 +1,192 @@ + +[ + { + "qpu_type": ["ideal"], + "t_gate_1qb" : [null], + "t_gate_2qbs" : [null], + "t_readout": [null], + "depol_channel" : [{ + "active": false, + "error_gate_1qb" : null, + "error_gate_2qbs" : null + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": false, + "t1" : null, + "t2" : null + }], + "meas": [{ + "active":false, + "readout_error": null + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": false, + "t1" : null, + "t2" : null + }], + "meas": [{ + "active":false, + "readout_error": null + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": true, + "dephasing_channel": false, + "t1" : 0.2e6, + "t2" : null + }], + "meas": [{ + "active":false, + "readout_error": null + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": true, + "t1" : 0.2e6, + "t2" : 0.1e6 + }], + "meas": [{ + "active":false, + "readout_error": null + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": true, + "dephasing_channel": true, + "t1" : 0.2e6, + "t2" : 0.1e6 + }], + "meas": [{ + "active":false, + "readout_error": null + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": false, + "t1" : null, + "t2" : null + }], + "meas": [{ + "active":true, + "readout_error": 1.370e-2 + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": true, + "error_gate_1qb" : 1.0e-4, + "error_gate_2qbs" : 1.0e-3 + }], + "idle" : [{ + "amplitude_damping": true, + "dephasing_channel": true, + "t1" : 0.2e6, + "t2" : 0.1e6 + }], + "meas": [{ + "active":true, + "readout_error": 1.370e-2 + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": false, + "error_gate_1qb" : null, + "error_gate_2qbs" : null + }], + "idle" : [{ + "amplitude_damping": true, + "dephasing_channel": true, + "t1" : 0.2e6, + "t2" : 0.1e6 + }], + "meas": [{ + "active":true, + "readout_error": 1.370e-2 + }] + }, + { + "qpu_type": ["noisy"], + "t_gate_1qb" : [35], + "t_gate_2qbs" : [660], + "t_readout": [4000], + "depol_channel" : [{ + "active": false, + "error_gate_1qb" : null, + "error_gate_2qbs" : null + }], + "idle" : [{ + "amplitude_damping": false, + "dephasing_channel": false, + "t1" : null, + "t2" : null + }], + "meas": [{ + "active":true, + "readout_error": 1.370e-2 + }] + } +] diff --git a/tnbs/BTC_01_PL/PL/qpu/select_qpu.py b/tnbs/BTC_01_PL/PL/qpu/select_qpu.py new file mode 100644 index 0000000..7109407 --- /dev/null +++ b/tnbs/BTC_01_PL/PL/qpu/select_qpu.py @@ -0,0 +1,130 @@ +""" +This module implements the select_qpu function that allows to the user +select a complete QPU. The input of this function is a Python dictionary +with the following keys: + + **qpu_type** + The value is a Python string for selecting the type of QPU. The + values can be: *c, python, linalg, mps, qlmass_linalg, qlmass_mps* + for using with pure ideal QPU (the get_qpu function from + QQuantLib.qpu.get_qpu module is used for getting the QPU). + Additionally, the values can be: *ideal* for using an ideal qpu + with a Toffoli rewritter pluging or *noisy* for configuring and + using a noisy QPU. In both cases the create_qpu function from + QQuantLib.qpu.model_noise module is used for creating the QPU. + + **t_gate_1qb** + For setting the time for the 1-qubit gates (in ns). Only valid + if *qpu_type* is noisy. + + **t_gate_2qbs** + For setting the time for the 2-qubit gates (in ns). Only valid + if *qpu_type* is noisy. + + **t_readout** + For setting the time for the measuring operations (in ns). Only + valid if *qpu_type* is noisy. + + **depol_channel** + For setting the parameters for a depolarizing channel. The value + is a complete dictionary with the following keys: **active** + the boolean key for activating or not the channel. **error_gate_1qb** + error for 1-qubit gates. **error_gate_2qbs** error for 2-qubits + gates. + + **idle** + For setting the parameters for idle qubits. The value is a + complete dictionary with the following keys: **amplitude_damping** + the boolean key for activating or not an Amplitude Damping channel. + **dephasing_channel** boolean key for activating or not a + Dephasing channel. **t1** time T1 of the qubits (in ns) + **t2** time T2 of the qubits (in nsa). + + **meas** + For setting the parameters for a measuring error. The value is a + complete dictionary with the following keys: **active** boolean + key for activating or not this error. **readout_error** measuring + error. +""" + +def select_qpu(hw_cfg): + """ + This function allows to select a QPU (a ideal or a noisy one). + + Parameters + ---------- + + hw_cfg : dict + Python dictionary for configuring a complete (ideal or noisy) + QPU. When an "ideal" QPU is selected the get_qpu from get_qpu + module is used. If a "noisy" QPU is selected then the differents + keys of the dictionary are used for configruing a noisy hardware + model using functions from model_noise module. + """ + + if hw_cfg["qpu_type"] in ["noisy", "ideal"]: + from model_noise import create_qpu + qpu = create_qpu(hw_cfg) + else: + from qpu.get_qpu import get_qpu + qpu = get_qpu(hw_cfg["qpu_type"]) + return qpu + +if __name__ == "__main__": + import json + import argparse + import sys + from benchmark_utils import combination_for_list + + parser = argparse.ArgumentParser() + parser.add_argument( + "--count", + dest="count", + default=False, + action="store_true", + help="For counting elements on the list", + ) + parser.add_argument( + "--print", + dest="print", + default=False, + action="store_true", + help="For printing " + ) + parser.add_argument( + "-id", + dest="id", + type=int, + help="For executing only one element of the list", + default=None, + ) + parser.add_argument( + "-json_qpu", + dest="json_qpu", + type=str, + default="jsons/qpu.json", + help="JSON with the qpu configuration", + ) + parser.add_argument( + "--exe", + dest="execution", + default=False, + action="store_true", + help="For executing program", + ) + args = parser.parse_args() + print(args) + with open(args.json_qpu) as json_file: + noisy_cfg = json.load(json_file) + final_list = combination_for_list(noisy_cfg) + if args.count: + print(len(final_list)) + if args.print: + if args.id is not None: + print(final_list[args.id]) + else: + print(final_list) + if args.execution: + if args.id is not None: + print(select_qpu(final_list[args.id])) + diff --git a/tnbs/BTC_01_PL/get_qpu.py b/tnbs/BTC_01_PL/get_qpu.py deleted file mode 100644 index 3a09fca..0000000 --- a/tnbs/BTC_01_PL/get_qpu.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Selector for QPU. -""" - -def get_qpu(qpu=None): - """ - Function for selecting solver. - - Parameters - ---------- - - qpu : str - * qlmass: for trying to use QLM as a Service connection - to CESGA QLM - * python: for using PyLinalg simulator. - * c: for using CLinalg simulator - * mps: for using mps - - Returns - ---------- - - linal_qpu : solver for quantum jobs - """ - - if qpu is None: - raise ValueError( - "qpu CAN NOT BE NONE. Please select one of the three" + - " following options: qlmass, python, c") - if qpu == "qlmass_linalg": - try: - from qlmaas.qpus import LinAlg - linalg_qpu = LinAlg() - except (ImportError, OSError) as exception: - raise ImportError( - "Problem Using QLMaaS. Please create config file" + - "or use mylm solver") from exception - elif qpu == "qlmass_mps": - try: - from qlmaas.qpus import MPS - #linalg_qpu = MPS(lnnize=True) - linalg_qpu = MPS() - except (ImportError, OSError) as exception: - raise ImportError( - "Problem Using QLMaaS. Please create config file" + - "or use mylm solver") from exception - elif qpu == "python": - from qat.qpus import PyLinalg - linalg_qpu = PyLinalg() - elif qpu == "c": - from qat.qpus import CLinalg - linalg_qpu = CLinalg() - elif qpu == "linalg": - from qat.qpus import LinAlg - linalg_qpu = LinAlg() - elif qpu == "mps": - from qat.qpus import MPS - linalg_qpu = MPS() - return linalg_qpu diff --git a/tnbs/BTC_01_PL/my_benchmark_execution.py b/tnbs/BTC_01_PL/my_benchmark_execution.py index 365fc59..1af52bb 100644 --- a/tnbs/BTC_01_PL/my_benchmark_execution.py +++ b/tnbs/BTC_01_PL/my_benchmark_execution.py @@ -9,7 +9,6 @@ # from copy import deepcopy import pandas as pd -from get_qpu import get_qpu l_sys = sys.path l_path = l_sys[['BTC_01' in i for i in l_sys].index(True)] sys.path.append(l_path+'/PL') @@ -163,7 +162,7 @@ def summarize_results(**kwargs): pdf = pd.read_csv(csv_results, index_col=0, sep=";") pdf["classic_time"] = pdf["elapsed_time"] - pdf["quantum_time"] - columns = ["n_qbits", "load_method", "KS", "KL", "chi2", "p_value", \ + columns = ["n_qbits", "load_method", "KS", "KL", \ "elapsed_time", "quantum_time", "classic_time"] pdf = pdf[columns] results = pdf.groupby(["load_method", "n_qbits"]).agg( @@ -294,15 +293,32 @@ def exe(self): if __name__ == "__main__": + import json + from PL.qpu.select_qpu import select_qpu + from PL.qpu.benchmark_utils import combination_for_list + ############## CONFIGURE THE BTC ################### kernel_configuration = { "load_method" : "multiplexor", - "qpu" : "c", #"c", python, qlmass, default "relative_error": None, "absolute_error": None } + # Base name for files name = "PL_{}".format(kernel_configuration["load_method"]) - + # List of qubits to benchmark + list_of_qbits = [6] + # Configuring the QPU + json_qpu_file = "./PL/qpu/qpu_ideal.json" + with open(json_qpu_file) as json_file: + qpu_cfg = json.load(json_file) + # The desired qpu should be provided + qpu_conf = combination_for_list(qpu_cfg)[0] + kernel_configuration.update({"qpu": select_qpu(qpu_conf)}) + ############## CONFIGURE THE BTC ################### + + + ############## CONFIGURE THE BENCHMARK EXECUTION ################# + # For TNBS guidelines following configuration SHOULD NOT BE CHANGED benchmark_arguments = { #Pre benchmark configuration "pre_benchmark": True, @@ -319,17 +335,22 @@ def exe(self): "min_meas": None, "max_meas": None, #List number of qubits tested - "list_of_qbits": [4], + "list_of_qbits": list_of_qbits, } + ############## CONFIGURE THE BENCHMARK EXECUTION ################# - # Selecting the QPU - kernel_configuration.update({"qpu": get_qpu(kernel_configuration['qpu'])}) #Configuration for the benchmark kernel benchmark_arguments.update({"kernel_configuration": kernel_configuration}) # Create Folder for storing results if not os.path.exists(benchmark_arguments["saving_folder"]): os.mkdir(benchmark_arguments["saving_folder"]) + # Store the QPU configuration + qpu_file = benchmark_arguments["saving_folder"] + \ + "qpu_configuration.json" + with open(qpu_file, "w") as outfile: + json.dump(qpu_conf, outfile) + # BENCHMARK EXECUTION ae_bench = KERNEL_BENCHMARK(**benchmark_arguments) ae_bench.exe() diff --git a/tnbs/BTC_01_PL/my_benchmark_summary.py b/tnbs/BTC_01_PL/my_benchmark_summary.py index 7d16e7c..af0ed5d 100644 --- a/tnbs/BTC_01_PL/my_benchmark_summary.py +++ b/tnbs/BTC_01_PL/my_benchmark_summary.py @@ -26,7 +26,6 @@ def summarize_results(**kwargs): load_methods = list(set(pdf["load_method"])) list_of_metrics = [ "KS", "KL", - "chi2", "p_value" ]