From b7dab2d8b7780d13e511f4fb2c71aa477bbd67fe Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 11 Jul 2023 18:39:33 +0200 Subject: [PATCH] Update RE application samples to use new features in Q# and azure_quantum (#811) * Use new Q# operation. * Use new summary table. * Use constraints and summary table in dynamics sample. * Summary table. * Explain logical_depth_factor. * Add link to paper. * Address comments. --- .../estimation-chemistry.ipynb | 67 ++---- .../estimation-dynamics.ipynb | 217 +++++++----------- .../estimation-factoring.ipynb | 137 +++-------- 3 files changed, 127 insertions(+), 294 deletions(-) diff --git a/samples/azure-quantum/resource-estimation/estimation-chemistry.ipynb b/samples/azure-quantum/resource-estimation/estimation-chemistry.ipynb index 66a8081bf710..2689cf6f49d9 100644 --- a/samples/azure-quantum/resource-estimation/estimation-chemistry.ipynb +++ b/samples/azure-quantum/resource-estimation/estimation-chemistry.ipynb @@ -188,7 +188,7 @@ "source": [ "## Analyzing the results\n", "\n", - "Now that the results have been computed, we display them in a summary table. For this purpose we are creating a reusable `dashboard` function that is creating an HTML display from a pandas data frame and the resource estimation tables." + "Finally, we are presenting the experimental results using a summary table." ] }, { @@ -199,52 +199,7 @@ "source": [ "labels = [\"Gate-based µs, 10⁻³\", \"Gate-based µs, 10⁻⁴\", \"Gate-based ns, 10⁻³\", \"Gate-based ns, 10⁻⁴\", \"Majorana ns, 10⁻⁴\", \"Majorana ns, 10⁻⁶\"]\n", "\n", - "def dashboard(results):\n", - " def get_row(result):\n", - " # Extract raw data from result dictionary\n", - " logical_qubits = result[\"physicalCounts\"][\"breakdown\"][\"algorithmicLogicalQubits\"]\n", - " logical_depth = result[\"physicalCounts\"][\"breakdown\"][\"logicalDepth\"]\n", - " num_tstates = result[\"physicalCounts\"][\"breakdown\"][\"numTstates\"]\n", - " code_distance = result[\"logicalQubit\"][\"codeDistance\"]\n", - " num_tfactories = result[\"physicalCounts\"][\"breakdown\"][\"numTfactories\"]\n", - " tfactory_fraction = (result[\"physicalCounts\"][\"breakdown\"][\"physicalQubitsForTfactories\"] / result[\"physicalCounts\"][\"physicalQubits\"]) * 100\n", - " physical_qubits = result[\"physicalCounts\"][\"physicalQubits\"]\n", - " runtime = result[\"physicalCounts\"][\"runtime\"]\n", - "\n", - " # Format some entries\n", - " logical_depth_formatted = f\"{logical_depth:.1e}\"\n", - " num_tstates_formatted = f\"{num_tstates:.1e}\"\n", - " tfactory_fraction_formatted = f\"{tfactory_fraction:.1f}%\"\n", - " physical_qubits_formatted = f\"{physical_qubits / 1e6:.2f}M\"\n", - "\n", - " # Make runtime human readable; we find the largest units for which the\n", - " # runtime has a value that is larger than 1.0. For that unit we are\n", - " # rounding the value and append the unit suffix.\n", - " units = [(\"nanosecs\", 1), (\"microsecs\", 1000), (\"millisecs\", 1000), (\"secs\", 1000), (\"mins\", 60), (\"hours\", 60), (\"days\", 24), (\"years\", 365)]\n", - " runtime_formatted = runtime\n", - " for idx in range(1, len(units)):\n", - " if runtime_formatted / units[idx][1] < 1.0:\n", - " runtime_formatted = f\"{round(runtime_formatted) % units[idx][1]} {units[idx - 1][0]}\"\n", - " break\n", - " else:\n", - " runtime_formatted = runtime_formatted / units[idx][1]\n", - "\n", - " # special case for years\n", - " if isinstance(runtime_formatted, float):\n", - " runtime_formatted = f\"{round(runtime_formatted)} {units[-1][0]}\"\n", - "\n", - " # Append all extracted and formatted data to data array\n", - " return (logical_qubits, logical_depth_formatted, num_tstates_formatted, code_distance, num_tfactories, tfactory_fraction_formatted, physical_qubits_formatted, runtime_formatted)\n", - "\n", - " data = [get_row(results.data(index)) for index in range(len(results))]\n", - "\n", - " # Create data frame with explicit column names and configuration names extracted from array\n", - " import pandas as pd\n", - " df = pd.DataFrame(data, columns=[\"Logical qubits\", \"Logical depth\", \"T states\", \"Code distance\", \"T factories\", \"T factory fraction\", \"Physical qubits\", \"Physical runtime\"], index=labels)\n", - "\n", - " return df\n", - "\n", - "dashboard(results)" + "results.summary_data_frame(labels=labels)" ] }, { @@ -303,6 +258,12 @@ "source": [ "In this notebook, you've estimated the quantum computing requirements to calculate the energy of a Hamiltonian. Nice job! 👏🏽\n", "\n", + "The numbers for the XVIII-cas4-fb-64e-56o instance roughly match the numbers in\n", + "the paper [Assessing requirements for scaling quantum computers to real-world\n", + "impact](https://aka.ms/AQ/RE/Paper), as we incorporated a few improvements in\n", + "the implementation of the double-factorized chemistry algorithm as compared to\n", + "the version used when the paper was published.\n", + "\n", "We hope that this notebook was helpful to you. Here are some suggestions for next steps:\n", "* Try to estimate some custom FCIDUMP files\n", "* Investigate the details of resource estimation by exploring the detailed resource estimation tables\n", @@ -327,10 +288,10 @@ } ], "metadata": { - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 1 + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 1 } diff --git a/samples/azure-quantum/resource-estimation/estimation-dynamics.ipynb b/samples/azure-quantum/resource-estimation/estimation-dynamics.ipynb index f8b8ce0698d8..ded643f595c3 100644 --- a/samples/azure-quantum/resource-estimation/estimation-dynamics.ipynb +++ b/samples/azure-quantum/resource-estimation/estimation-dynamics.ipynb @@ -20,10 +20,9 @@ "metadata": {}, "outputs": [], "source": [ - "import qsharp.azure\n", - "targets = qsharp.azure.connect(\n", - " resourceId=\"\",\n", - " location=\"\")" + "from azure.quantum import Workspace\n", + "from azure.quantum.target.microsoft import MicrosoftEstimator, QubitParams, QECScheme\n", + "import qsharp" ] }, { @@ -32,8 +31,19 @@ "metadata": {}, "outputs": [], "source": [ - "qsharp.packages.add(\"Microsoft.Quantum.Numerics\")\n", - "qsharp.azure.target(\"microsoft.estimator\")" + "workspace = Workspace (\n", + " resource_id = \"\",\n", + " location = \"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "qsharp.packages.add(\"Microsoft.Quantum.Numerics\")" ] }, { @@ -226,21 +236,7 @@ "- `N`: size of the square lattice.\n", "- `totTime`: the number of Trotter steps.\n", "- `dt` : the step size for the simulation, sometimes denoted as $\\Delta$.\n", - "- `eps`: the precision for arbitrary rotations.\n", - "\n", - "The last parameter `noops` is used in a way to implicitly slow down the\n", - "algorithm. When estimating physical resources, the Resource Estimator is\n", - "computing the number of T factory invocations in a way that the total runtime of\n", - "all T factories does not exceed the algorithm runtime. In order to achieve the\n", - "required number of T states, the T factories are copied sufficiently many times.\n", - "In order to obtain fewer copies, we can extend the algorithm runtime. One way\n", - "to do this, without increasing the number of T states, is by adding single qubit\n", - "measurements. Therefore we model such no-operations (NoOps) in the program by\n", - "measuring one qubit `noops` many times at the end of the program.\n", - "\n", - "ℹ️ In upcoming releases of the Resource Estimator we will improve the\n", - "configuration of optimization objectives for T factories and the overall\n", - "algorithm." + "- `eps`: the precision for arbitrary rotations." ] }, { @@ -252,7 +248,7 @@ "%%qsharp\n", "open Microsoft.Quantum.Math;\n", "\n", - "operation IsingModel2DSim(N : Int, J : Double, g : Double, totTime : Double, dt : Double, eps : Double, noops : Int) : Unit {\n", + "operation IsingModel2DSim(N : Int, J : Double, g : Double, totTime : Double, dt : Double, eps : Double) : Unit {\n", " use qs = Qubit[N * N];\n", " let len = Length(qs);\n", "\n", @@ -274,11 +270,6 @@ " }\n", " }\n", " }\n", - "\n", - " // apply `noops` NoOps to extend algorithm runtime\n", - " for _ in 1..noops {\n", - " Ignore(M(qs[0]));\n", - " }\n", "}" ] }, @@ -288,7 +279,12 @@ "source": [ "## Running the experiment\n", "\n", - "Next, we are estimating the physical resource estimates to simulate the Ising model Hamiltonian for a $10 \\times 10$ lattice with $J = g = 1.0$, total time $20$, step size $0.25$, and `eps` ${}=0.001$. To do this, we first create a Q# operation for this instance that takes as single input argument the number of NoOps, which will be job parameter dependent." + "Next, we are estimating the physical resource estimates to simulate the Ising\n", + "model Hamiltonian for a $10 \\times 10$ lattice with $J = g = 1.0$, total time\n", + "$20$, step size $0.25$, and `eps` ${}=0.001$. As configurations for the\n", + "experiment we use all six pre-defined qubit parameters. As pre-defined QEC\n", + "scheme we are using `surface_code` with gate-based qubit parameters (default),\n", + "and `floquet_code` with Majorana based qubit parameters." ] }, { @@ -297,20 +293,32 @@ "metadata": {}, "outputs": [], "source": [ - "%%qsharp\n", - "operation Ising10(noops : Int) : Unit {\n", - " IsingModel2DSim(10, 1.0, 1.0, 20.0, 0.25, 0.001, noops);\n", - "}" + "estimator = MicrosoftEstimator(workspace)\n", + "\n", + "labels = [\"Gate-based µs, 10⁻³\", \"Gate-based µs, 10⁻⁴\", \"Gate-based ns, 10⁻³\", \"Gate-based ns, 10⁻⁴\", \"Majorana ns, 10⁻⁴\", \"Majorana ns, 10⁻⁶\"]\n", + "\n", + "params = estimator.make_params(num_items=6)\n", + "params.arguments[\"N\"] = 10\n", + "params.arguments[\"J\"] = 1.0\n", + "params.arguments[\"g\"] = 1.0\n", + "params.arguments[\"totTime\"] = 20.0\n", + "params.arguments[\"dt\"] = 0.25\n", + "params.arguments[\"eps\"] = 0.001\n", + "params.items[0].qubit_params.name = QubitParams.GATE_US_E3\n", + "params.items[1].qubit_params.name = QubitParams.GATE_US_E4\n", + "params.items[2].qubit_params.name = QubitParams.GATE_NS_E3\n", + "params.items[3].qubit_params.name = QubitParams.GATE_NS_E4\n", + "params.items[4].qubit_params.name = QubitParams.MAJ_NS_E4\n", + "params.items[4].qec_scheme.name = QECScheme.FLOQUET_CODE\n", + "params.items[5].qubit_params.name = QubitParams.MAJ_NS_E6\n", + "params.items[5].qec_scheme.name = QECScheme.FLOQUET_CODE" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "As configurations for the experiment we use all six pre-defined qubit\n", - "parameters. As pre-defined QEC scheme we are using `surface_code` with\n", - "gate-based qubit parameters, and `floquet_code` with Majorana based qubit\n", - "parameters." + "We are submitting a resource estimation job with all target parameter configurations." ] }, { @@ -319,25 +327,15 @@ "metadata": {}, "outputs": [], "source": [ - "labels = [\"Gate-based µs, 10⁻³\", \"Gate-based µs, 10⁻⁴\", \"Gate-based ns, 10⁻³\", \"Gate-based ns, 10⁻⁴\", \"Majorana ns, 10⁻⁴\", \"Majorana ns, 10⁻⁶\"]\n", - "\n", - "target_params = [\n", - " {\"qubitParams\": {\"name\": \"qubit_gate_us_e3\"}},\n", - " {\"qubitParams\": {\"name\": \"qubit_gate_us_e4\"}},\n", - " {\"qubitParams\": {\"name\": \"qubit_gate_ns_e3\"}},\n", - " {\"qubitParams\": {\"name\": \"qubit_gate_ns_e4\"}},\n", - " {\"qecScheme\": {\"name\": \"floquet_code\"}, \"qubitParams\": {\"name\": \"qubit_maj_ns_e4\"}},\n", - " {\"qecScheme\": {\"name\": \"floquet_code\"}, \"qubitParams\": {\"name\": \"qubit_maj_ns_e6\"}}\n", - "]" + "job = estimator.submit(IsingModel2DSim, input_params=params)\n", + "results = job.get_results()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We are submitting a resource estimation job with all target parameter\n", - "configurations. We create corresponding item objects by setting the input\n", - "argument `noops` to `0` for all items." + "Finally, we are presenting the experimental results using a summary table." ] }, { @@ -346,20 +344,40 @@ "metadata": {}, "outputs": [], "source": [ - "items = [{\"arguments\": [{\"name\": \"noops\", \"value\": 0, \"type\": \"Int\"}], **params} for params in target_params]\n", - "results = qsharp.azure.execute(Ising10, jobParams={\"items\": items})" + "results.summary_data_frame(labels=labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, we present the estimation results. First, we explicitly extract some\n", - "of the results in a summary table. Some values are using a user-defined\n", - "formatting. Then, we display full details for all qubit parameters in tables\n", - "that are constructed using the built-in resource estimation table feature. You\n", - "can re-use this `dashboard` function in other Q# + Python notebooks to display\n", - "similar tables your experiments." + "From the results we can observe that a large fraction of physical qubits is used\n", + "for the T factories. To understand why, it's important to remark that the\n", + "overall algorithm runtime is determined based on the number of logical\n", + "operations (also called logical cycles or logical depth). The runtime limits\n", + "the number of invocations of a single T factory. The total number of T factory\n", + "copies is computed based on the total number of required T states divided by the\n", + "number of possible invocations. Therefore, if the algorithm would run longer, a\n", + "T factory can be invoked more often, which may allow to compute all required T\n", + "states with less T factory copies.\n", + "\n", + "Since T factory fraction is high, while at the same time the physical runtime is\n", + "relatively small, this is a good opportunity for a space-time optimization based\n", + "on the logical depth. We can make an algorithm run longer, by inserting no-op\n", + "(no operation or idle) operations. We do this using the `logical_depth_factor`\n", + "constraint. For example, a value of 2 means that the number of cycles should be\n", + "twice as much, i.e., one no-op per operation; or, a value of 1.5 means that the\n", + "number of cycles is 50% more, i.e., one no-op for every two operations.\n", + "\n", + "Please note that the algorithm runtime may increase by a larger factor than the\n", + "`logical_depth_factor`. This is because no-ops also can incur logical errors,\n", + "and therefore the required logical error rate is lower, which in turn may\n", + "increase the required code distance, therefore leading a to a longer execution\n", + "time of a logical cycle.\n", + "\n", + "In the balanced implementation that is described in the paper, we increase the\n", + "logical depth by a factor of 10. We do this by updating the `params` variable.\n", + "All other parameters remain unchanged." ] }, { @@ -368,69 +386,17 @@ "metadata": {}, "outputs": [], "source": [ - "def dashboard(results):\n", - " def get_row(result):\n", - " # Extract raw data from result dictionary\n", - " logical_qubits = result[\"physicalCounts\"][\"breakdown\"][\"algorithmicLogicalQubits\"]\n", - " logical_depth = result[\"physicalCounts\"][\"breakdown\"][\"logicalDepth\"]\n", - " num_tstates = result[\"physicalCounts\"][\"breakdown\"][\"numTstates\"]\n", - " code_distance = result[\"logicalQubit\"][\"codeDistance\"]\n", - " num_tfactories = result[\"physicalCounts\"][\"breakdown\"][\"numTfactories\"]\n", - " tfactory_fraction = (result[\"physicalCounts\"][\"breakdown\"][\"physicalQubitsForTfactories\"] / result[\"physicalCounts\"][\"physicalQubits\"]) * 100\n", - " physical_qubits = result[\"physicalCounts\"][\"physicalQubits\"]\n", - " runtime = result[\"physicalCounts\"][\"runtime\"]\n", - "\n", - " # Format some entries\n", - " logical_depth_formatted = f\"{logical_depth:.1e}\"\n", - " num_tstates_formatted = f\"{num_tstates:.1e}\"\n", - " tfactory_fraction_formatted = f\"{tfactory_fraction:.1f}%\"\n", - " physical_qubits_formatted = f\"{physical_qubits / 1e6:.2f}M\"\n", - "\n", - " # Make runtime human readable; we find the largest units for which the\n", - " # runtime has a value that is larger than 1.0. For that unit we are\n", - " # rounding the value and append the unit suffix.\n", - " units = [(\"nanosecs\", 1), (\"microsecs\", 1000), (\"millisecs\", 1000), (\"secs\", 1000), (\"mins\", 60), (\"hours\", 60), (\"days\", 24), (\"years\", 365)]\n", - " runtime_formatted = runtime\n", - " for idx in range(1, len(units)):\n", - " if runtime_formatted / units[idx][1] < 1.0:\n", - " runtime_formatted = f\"{round(runtime_formatted) % units[idx][1]} {units[idx - 1][0]}\"\n", - " break\n", - " else:\n", - " runtime_formatted = runtime_formatted / units[idx][1]\n", - "\n", - " # special case for years\n", - " if isinstance(runtime_formatted, float):\n", - " runtime_formatted = f\"{round(runtime_formatted)} {units[-1][0]}\"\n", - "\n", - " # Append all extracted and formatted data to data array\n", - " return (logical_qubits, logical_depth_formatted, num_tstates_formatted, code_distance, num_tfactories, tfactory_fraction_formatted, physical_qubits_formatted, runtime_formatted)\n", - "\n", - " data = [get_row(results.data(index)) for index in range(len(results))]\n", - "\n", - " # Create data frame with explicit column names and configuration names extracted from array\n", - " import pandas as pd\n", - " df = pd.DataFrame(data, columns=[\"Logical qubits\", \"Logical depth\", \"T states\", \"Code distance\", \"T factories\", \"T factory fraction\", \"Physical qubits\", \"Physical runtime\"], index=labels)\n", - "\n", - " from IPython.display import HTML\n", - "\n", - " html = f\"\"\"\n", - "

Summary

{df.to_html()}
\n", - "

Details

{results._repr_html_()}
\n", - " \"\"\"\n", - " \n", - " return HTML(html)\n", - "\n", - "dashboard(results)" + "params.constraints.logical_depth_factor = 10\n", + "\n", + "job = estimator.submit(IsingModel2DSim, input_params=params)\n", + "results_balanced = job.get_results()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, we rerun the experiment for the balanced implementation, a scenario in\n", - "which we slow down the algorithm runtime by a factor of 10. We achieve this by\n", - "inserting 9 times the logical depth of the current results as NoOps into the\n", - "algorithm, as described above." + "We print the results for the balanced implementation as a summary." ] }, { @@ -439,27 +405,17 @@ "metadata": {}, "outputs": [], "source": [ - "logical_depth = results[0]['physicalCounts']['breakdown']['logicalDepth']\n", - "\n", - "items = [{\"arguments\": [{\"name\": \"noops\", \"value\": 9 * logical_depth, \"type\": \"Int\"}], **params} for params in target_params]\n", - "results_balanced = qsharp.azure.execute(Ising10, jobParams={\"items\": items})" + "results_balanced.summary_data_frame(labels=labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We print the results for the balanced implementation with the dashboard as\n", - "before." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dashboard(results_balanced)" + "Note how the T factory fraction is much smaller now and the number of total\n", + "physical qubits decreased as a result. The logical depth increased exactly by a\n", + "factor of 10, whereas the runtime increased by a factor of at least 10, since in\n", + "most cases the code distance is higher." ] }, { @@ -475,7 +431,8 @@ "\n", "* explore how the results change by modifying the operation arguments of the Ising\n", " model instance\n", - "* explore space- and time-trade-offs by changing the number of NoOps\n", + "* explore space- and time-trade-offs by changing the value for\n", + " `logical_depth_factor`\n", "* use other or customized qubit parameters" ] } diff --git a/samples/azure-quantum/resource-estimation/estimation-factoring.ipynb b/samples/azure-quantum/resource-estimation/estimation-factoring.ipynb index bde38373a991..c6899de713c6 100644 --- a/samples/azure-quantum/resource-estimation/estimation-factoring.ipynb +++ b/samples/azure-quantum/resource-estimation/estimation-factoring.ipynb @@ -32,7 +32,8 @@ "outputs": [], "source": [ "from azure.quantum import Workspace\n", - "from azure.quantum.target.microsoft import MicrosoftEstimator" + "from azure.quantum.target.microsoft import MicrosoftEstimator, QubitParams, QECScheme\n", + "import qsharp" ] }, { @@ -60,7 +61,7 @@ "source": [ "## Extracting resource estimates from logical resource counts\n", "\n", - "We create a function that creates QIR bitcode from precomputed logical resource estimates. This function internally creates a small QIR program that leverages the low-level QIR function `__quantum__qis__applyunimplemented__body` that allows to _inject_ logical resource counts to a list of qubits." + "We create a Q# program that describes the algorithm in terms of precomputed logical resource estimates. To this end, we are using the [AccountForEstimates](https://learn.microsoft.com/qsharp/api/qsharp/microsoft.quantum.resourceestimation.accountforestimates) operation." ] }, { @@ -69,41 +70,17 @@ "metadata": {}, "outputs": [], "source": [ - "def logical_counts(\n", - " qubit_count: int = 0,\n", - " t_count: int = 0,\n", - " rotation_count: int = 0,\n", - " rotation_depth: int = 0,\n", - " ccz_count: int = 0,\n", - " measurement_count: int = 0\n", - "):\n", - " import textwrap\n", - "\n", - " ir = f\"\"\"\n", - " %Array = type opaque\n", - " %Qubit = type opaque\n", - " attributes #1 = {{ \"entry_point\" }}\n", - " declare %Array* @__quantum__rt__qubit_allocate_array(i64)\n", - " declare void @__quantum__rt__qubit_release_array(%Array*)\n", - " declare void @__quantum__qis__applyunimplemented__body(i64, i64, i64, i64, i64, %Array*)\n", - " define void @Project__Program() #1 {{\n", - " entry:\n", - " %target = call %Array* @__quantum__rt__qubit_allocate_array(i64 {qubit_count})\n", - " call void @__quantum__qis__applyunimplemented__body(i64 {t_count}, i64 {rotation_count}, i64 {rotation_depth}, i64 {ccz_count}, i64 {measurement_count}, %Array* %target)\n", - " call void @__quantum__rt__qubit_release_array(%Array* %target)\n", - " ret void\n", - " }}\n", - " \"\"\"\n", - "\n", - " # Support code to transition from pyqir-generator to pyqir package\n", - " try:\n", - " from pyqir.generator import ir_to_bitcode\n", - " except:\n", - " def ir_to_bitcode(ir):\n", - " from pyqir import Context, Module\n", - " return Module.from_ir(Context(), ir).bitcode\n", - "\n", - " return ir_to_bitcode(textwrap.dedent(ir))" + "%%qsharp\n", + "open Microsoft.Quantum.ResourceEstimation;\n", + "\n", + "operation FactoringFromLogicalCounts() : Unit {\n", + " use qubits = Qubit[12581];\n", + " \n", + " AccountForEstimates(\n", + " [TCount(12), RotationCount(12), RotationDepth(12),\n", + " CczCount(3731607428), MeasurementCount(1078154040)],\n", + " PSSPCLayout(), qubits);\n", + "}" ] }, { @@ -134,21 +111,21 @@ "\n", "params = estimator.make_params(num_items=6)\n", "params.error_budget = 0.333\n", - "params.items[0].qubit_params.name = \"qubit_gate_us_e3\"\n", - "params.items[1].qubit_params.name = \"qubit_gate_us_e4\"\n", - "params.items[2].qubit_params.name = \"qubit_gate_ns_e3\"\n", - "params.items[3].qubit_params.name = \"qubit_gate_ns_e4\"\n", - "params.items[4].qubit_params.name = \"qubit_maj_ns_e4\"\n", - "params.items[4].qec_scheme.name = \"floquet_code\"\n", - "params.items[5].qubit_params.name = \"qubit_maj_ns_e6\"\n", - "params.items[5].qec_scheme.name = \"floquet_code\"" + "params.items[0].qubit_params.name = QubitParams.GATE_US_E3\n", + "params.items[1].qubit_params.name = QubitParams.GATE_US_E4\n", + "params.items[2].qubit_params.name = QubitParams.GATE_NS_E3\n", + "params.items[3].qubit_params.name = QubitParams.GATE_NS_E4\n", + "params.items[4].qubit_params.name = QubitParams.MAJ_NS_E4\n", + "params.items[4].qec_scheme.name = QECScheme.FLOQUET_CODE\n", + "params.items[5].qubit_params.name = QubitParams.MAJ_NS_E6\n", + "params.items[5].qec_scheme.name = QECScheme.FLOQUET_CODE" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next we are submitting the resource estimation job based on logical resource counts that we have extracted for the pre-computed for the 2048-bit factoring instance." + "Next we are submitting the resource estimation job based on the Q# operation above." ] }, { @@ -157,14 +134,7 @@ "metadata": {}, "outputs": [], "source": [ - "bitcode = logical_counts(\n", - " qubit_count=12581,\n", - " t_count=12,\n", - " rotation_count=12,\n", - " rotation_depth=12,\n", - " ccz_count=3731607428,\n", - " measurement_count=1078154040)\n", - "job = estimator.submit(bitcode, input_params=params)\n", + "job = estimator.submit(FactoringFromLogicalCounts, input_params=params)\n", "results = job.get_results()\n" ] }, @@ -172,10 +142,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, we are presenting the experimental results using built-in resource\n", - "estimation tables as well as a custom summary table. For this purpose we are\n", - "creating a reusable `dashboard` function that is creating an HTML display from a\n", - "pandas data frame and the resource estimation tables." + "Finally, we are presenting the experimental results using a summary table." ] }, { @@ -184,59 +151,7 @@ "metadata": {}, "outputs": [], "source": [ - "def dashboard(results):\n", - " def get_row(result):\n", - " # Extract raw data from result dictionary\n", - " logical_qubits = result[\"physicalCounts\"][\"breakdown\"][\"algorithmicLogicalQubits\"]\n", - " logical_depth = result[\"physicalCounts\"][\"breakdown\"][\"logicalDepth\"]\n", - " num_tstates = result[\"physicalCounts\"][\"breakdown\"][\"numTstates\"]\n", - " code_distance = result[\"logicalQubit\"][\"codeDistance\"]\n", - " num_tfactories = result[\"physicalCounts\"][\"breakdown\"][\"numTfactories\"]\n", - " tfactory_fraction = (result[\"physicalCounts\"][\"breakdown\"][\"physicalQubitsForTfactories\"] / result[\"physicalCounts\"][\"physicalQubits\"]) * 100\n", - " physical_qubits = result[\"physicalCounts\"][\"physicalQubits\"]\n", - " runtime = result[\"physicalCounts\"][\"runtime\"]\n", - "\n", - " # Format some entries\n", - " logical_depth_formatted = f\"{logical_depth:.1e}\"\n", - " num_tstates_formatted = f\"{num_tstates:.1e}\"\n", - " tfactory_fraction_formatted = f\"{tfactory_fraction:.1f}%\"\n", - " physical_qubits_formatted = f\"{physical_qubits / 1e6:.2f}M\"\n", - "\n", - " # Make runtime human readable; we find the largest units for which the\n", - " # runtime has a value that is larger than 1.0. For that unit we are\n", - " # rounding the value and append the unit suffix.\n", - " units = [(\"nanosecs\", 1), (\"microsecs\", 1000), (\"millisecs\", 1000), (\"secs\", 1000), (\"mins\", 60), (\"hours\", 60), (\"days\", 24), (\"years\", 365)]\n", - " runtime_formatted = runtime\n", - " for idx in range(1, len(units)):\n", - " if runtime_formatted / units[idx][1] < 1.0:\n", - " runtime_formatted = f\"{round(runtime_formatted) % units[idx][1]} {units[idx - 1][0]}\"\n", - " break\n", - " else:\n", - " runtime_formatted = runtime_formatted / units[idx][1]\n", - "\n", - " # special case for years\n", - " if isinstance(runtime_formatted, float):\n", - " runtime_formatted = f\"{round(runtime_formatted)} {units[-1][0]}\"\n", - "\n", - " # Append all extracted and formatted data to data array\n", - " return (logical_qubits, logical_depth_formatted, num_tstates_formatted, code_distance, num_tfactories, tfactory_fraction_formatted, physical_qubits_formatted, runtime_formatted)\n", - "\n", - " data = [get_row(results.data(index)) for index in range(len(results))]\n", - "\n", - " # Create data frame with explicit column names and configuration names extracted from array\n", - " import pandas as pd\n", - " df = pd.DataFrame(data, columns=[\"Logical qubits\", \"Logical depth\", \"T states\", \"Code distance\", \"T factories\", \"T factory fraction\", \"Physical qubits\", \"Physical runtime\"], index=labels)\n", - "\n", - " from IPython.display import HTML\n", - "\n", - " html = f\"\"\"\n", - "

Summary

{df.to_html()}
\n", - "

Details

{results[:]._repr_html_()}\n", - " \"\"\"\n", - "\n", - " return HTML(html)\n", - "\n", - "dashboard(results)" + "results.summary_data_frame(labels=labels)" ] }, {