diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 73faa61..3f7179f 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ["3.11"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} @@ -23,4 +23,4 @@ jobs: pip install "black[jupyter]" - name: Check formating with black run: | - black algorithms qbraid_lab qbraid_sdk --check \ No newline at end of file + black algorithms qbraid_lab qbraid_sdk qbraid_qir --line-length=100 --check \ No newline at end of file diff --git a/README.md b/README.md index dfa1ee0..ef66aa1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,29 @@ -# qBraid Lab Demos + +# qBraid Demos and Tutorials + +Welcome to the qBraid Demos Repository! This repository contains a collection of Jupyter Notebooks showcasing how to use **qBraid's open-source SDKs** for quantum computing. It includes hands-on examples that demonstrate the integration of various tools with **qBraid-Lab**, making it easier to run quantum computing experiments seamlessly in the cloud. + [](https://account.qbraid.com?gitHubUrl=https://github.com/qBraid/qbraid-lab-demo.git) -qBraid is a cloud-based platform for quantum computing. +## Contents + +This repository features tutorials and examples for the following: + +- [**qBraid-SDK**](https://docs.qbraid.com/sdk/): Learn how to interact with quantum devices using the qBraid Runtime framework. +- [**qBraid-QIR**](https://docs.qbraid.com/qir/): Explore qBraid's Quantum Intermediate Representation (QIR) interface using familiar frameworks like OpenQASM 3 and Cirq. +- [**qBraid-CLI**](https://docs.qbraid.com/cli/): Understand how to manage quantum jobs and resources using qBraid's Command Line Interface. +- [**qBraid-Lab**](https://docs.qbraid.com/lab/) Integration: + - [**Quantum Jobs**](https://docs.qbraid.com/lab/user-guide/quantum-jobs): Learn how to submit and manage quantum jobs in qBraid Lab. + - [**GPUs**](https://docs.qbraid.com/lab/user-guide/gpus): Learn how to accelerate your quantum simulations using GPUs available through qBraid Lab. + +## Documentation and Resources + +For more information on qBraid and its tools, check out: + +- **qBraid Platform Documentation**: Comprehensive user guides and resources at [docs.qbraid.com](https://docs.qbraid.com/). +- **qBraid Software API Reference**: Detailed API documentation for the qBraid-SDK at [sdk.qbraid.com](https://sdk.qbraid.com/). +- **qBraid GitHub Community**: Join the discussion and contribute at [GitHub Community Page](https://github.com/qBraid/community). -This repository provides demos and tutorials on using the [qBraid SDK](https://github.com/qBraid/qBraid), [qBraid CLI](https://docs.qbraid.com/projects/cli/en/latest/cli/qbraid.html), and qBraid Lab features including [Quantum Jobs](https://docs.qbraid.com/projects/lab/en/latest/lab/quantum_jobs.html), and [GPUs](https://docs.qbraid.com/projects/lab/en/latest/lab/gpu.html). +## Contribution -For more resources and reference material, see [qBraid Docs](https://docs.qbraid.com/en/latest/). +Contributions to this repository are welcome! If you encounter any issues or would like to contribute improvements or new examples, please open an issue or submit a pull request. diff --git a/algorithms/quantum_opt_rl/QCO.ipynb b/algorithms/quantum_opt_rl/QCO.ipynb index bce0d12..754614f 100644 --- a/algorithms/quantum_opt_rl/QCO.ipynb +++ b/algorithms/quantum_opt_rl/QCO.ipynb @@ -230,9 +230,7 @@ "# Adjust the optimization level to see how the number of passes changes\n", "pass_manager = generate_preset_pass_manager(3, backend)\n", "\n", - "print(\n", - " f\"The pass manager for {FakeGuadalupeV2.backend_name} has the following passes: \\n\"\n", - ")\n", + "print(f\"The pass manager for {FakeGuadalupeV2.backend_name} has the following passes: \\n\")\n", "\n", "# Print out the passes in the pass manager\n", "for i, pass_ in enumerate(pass_manager.passes()):\n", @@ -406,9 +404,7 @@ "optimization_levels = [0, 1, 2, 3]\n", "\n", "\n", - "def optimize_circuits(\n", - " circuit: QuantumCircuit, optimization_levels: List[int]\n", - ") -> List[float]:\n", + "def optimize_circuits(circuit: QuantumCircuit, optimization_levels: List[int]) -> List[float]:\n", " \"\"\"Optimize the circuit at each optimization level\"\"\"\n", " # Create an empty list to store the times\n", " times = []\n", @@ -856,9 +852,7 @@ ], "source": [ "# 1q gate optimization\n", - "commutative_cancellation = PassManager(\n", - " [CommutativeCancellation(basis_gates=[\"cx\", \"u\", \"id\"])]\n", - ")\n", + "commutative_cancellation = PassManager([CommutativeCancellation(basis_gates=[\"cx\", \"u\", \"id\"])])\n", "\n", "# Get the result circuit\n", "result = commutative_cancellation.run(circuit)\n", @@ -1366,11 +1360,11 @@ "metadata": {}, "outputs": [], "source": [ - "sub_batch_size = 64 # cardinality of the sub-samples gathered from the current data in the inner loop\n", - "num_epochs = 10 # optimization steps per batch of data collected\n", - "clip_epsilon = (\n", - " 0.2 # clip value for PPO loss: see the equation in the intro for more context.\n", + "sub_batch_size = (\n", + " 64 # cardinality of the sub-samples gathered from the current data in the inner loop\n", ")\n", + "num_epochs = 10 # optimization steps per batch of data collected\n", + "clip_epsilon = 0.2 # clip value for PPO loss: see the equation in the intro for more context.\n", "gamma = 0.99\n", "lmbda = 0.95\n", "entropy_eps = 1e-4" @@ -1623,9 +1617,7 @@ ], "source": [ "actor_net = agent.model\n", - "policy_module = TensorDictModule(\n", - " actor_net, in_keys=[\"observation\"], out_keys=[\"loc\", \"scale\"]\n", - ")\n", + "policy_module = TensorDictModule(actor_net, in_keys=[\"observation\"], out_keys=[\"loc\", \"scale\"])\n", "print(env.action_spec.shape[-1])\n", "\n", "policy_module = ProbabilisticActor(\n", @@ -1767,9 +1759,7 @@ } ], "source": [ - "advantage_module = GAE(\n", - " gamma=gamma, lmbda=lmbda, value_network=value_module, average_gae=True\n", - ")\n", + "advantage_module = GAE(gamma=gamma, lmbda=lmbda, value_network=value_module, average_gae=True)\n", "print(advantage_module.__dict__)\n", "lr = 3e-4\n", "\n", @@ -1789,9 +1779,7 @@ "# loss_module = loss_module.set_keys\n", "\n", "optim = torch.optim.Adam(loss_module.parameters(), lr)\n", - "scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(\n", - " optim, total_frames // frames_per_batch, 0.0\n", - ")" + "scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optim, total_frames // frames_per_batch, 0.0)" ] }, { @@ -1828,9 +1816,7 @@ " subdata = replay_buffer.sample(sub_batch_size)\n", " loss_vals = loss_module(subdata.to(device))\n", " loss_value = (\n", - " loss_vals[\"loss_objective\"]\n", - " + loss_vals[\"loss_critic\"]\n", - " + loss_vals[\"loss_entropy\"]\n", + " loss_vals[\"loss_objective\"] + loss_vals[\"loss_critic\"] + loss_vals[\"loss_entropy\"]\n", " )\n", "\n", " # Optimization: backward, grad clipping and optimization step\n", @@ -1843,9 +1829,7 @@ "\n", " logs[\"reward\"].append(tensordict_data[\"next\", \"reward\"].mean().item())\n", " pbar.update(tensordict_data.numel() * frame_skip)\n", - " cum_reward_str = (\n", - " f\"average reward={logs['reward'][-1]: 4.4f} (init={logs['reward'][0]: 4.4f})\"\n", - " )\n", + " cum_reward_str = f\"average reward={logs['reward'][-1]: 4.4f} (init={logs['reward'][0]: 4.4f})\"\n", " logs[\"step_count\"].append(tensordict_data[\"step_count\"].max().item())\n", " stepcount_str = f\"step count (max): {logs['step_count'][-1]}\"\n", " logs[\"lr\"].append(optim.param_groups[0][\"lr\"])\n", @@ -1861,9 +1845,7 @@ " # execute a rollout with the trained policy\n", " eval_rollout = env.rollout(1000, policy_module)\n", " logs[\"eval reward\"].append(eval_rollout[\"next\", \"reward\"].mean().item())\n", - " logs[\"eval reward (sum)\"].append(\n", - " eval_rollout[\"next\", \"reward\"].sum().item()\n", - " )\n", + " logs[\"eval reward (sum)\"].append(eval_rollout[\"next\", \"reward\"].sum().item())\n", " logs[\"eval step_count\"].append(eval_rollout[\"step_count\"].max().item())\n", " eval_str = (\n", " f\"eval cumulative reward: {logs['eval reward (sum)'][-1]: 4.4f} \"\n", diff --git a/algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/quantum_env.py b/algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/quantum_env.py index 8a979d5..5fc87f8 100644 --- a/algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/quantum_env.py +++ b/algorithms/quantum_opt_rl/gym-examples/gym_examples/envs/quantum_env.py @@ -89,12 +89,8 @@ def create_random_circuit(self, seed: Optional[int] = None) -> QuantumCircuit: """ if seed is not None: np.random.seed(seed) - qc_1 = random_circuit( - self.num_qubits, np.random.randint(self.min_depth, self.max_depth) - ) - qc_2 = random_circuit( - self.num_qubits, np.random.randint(self.min_depth, self.max_depth) - ) + qc_1 = random_circuit(self.num_qubits, np.random.randint(self.min_depth, self.max_depth)) + qc_2 = random_circuit(self.num_qubits, np.random.randint(self.min_depth, self.max_depth)) qc_1.compose(qc_2, inplace=True) @@ -121,9 +117,7 @@ def _create_tensor_from_circuit(self, circuit: QuantumCircuit) -> torch.Tensor: """ # The tensor is of shape (num_qubits, num_gates, num_params) - circuit_tensor = torch.zeros( - (circuit.num_qubits, len(self.qiskit_gates), self.num_actions) - ) + circuit_tensor = torch.zeros((circuit.num_qubits, len(self.qiskit_gates), self.num_actions)) for _, op in enumerate(circuit): name = op.operation.name @@ -142,9 +136,7 @@ def _create_tensor_from_circuit(self, circuit: QuantumCircuit) -> torch.Tensor: def get_qiskit_gates(self, seed: Optional[int] = None): """Returns a dictionary of all qiskit gates with random parameters""" qiskit_gates = { - attr: None - for attr in dir(standard_gates) - if attr[0] in string.ascii_uppercase + attr: None for attr in dir(standard_gates) if attr[0] in string.ascii_uppercase } # Add random parameters to gates for circuit generation @@ -156,9 +148,7 @@ def get_qiskit_gates(self, seed: Optional[int] = None): ] params = self._generate_params(varnames, seed=seed) qiskit_gates[gate] = getattr(standard_gates, gate)(**params) - qiskit_gates = OrderedDict( - {v.name: v for _, v in qiskit_gates.items() if v is not None} - ) + qiskit_gates = OrderedDict({v.name: v for _, v in qiskit_gates.items() if v is not None}) # Add iSwap gate qiskit_gates["iswap"] = iSwapGate() return qiskit_gates diff --git a/qbraid_lab/fire_opal/get-started.ipynb b/qbraid_lab/fire_opal/get-started.ipynb index 415953e..934aa90 100644 --- a/qbraid_lab/fire_opal/get-started.ipynb +++ b/qbraid_lab/fire_opal/get-started.ipynb @@ -354,9 +354,7 @@ "metadata": {}, "outputs": [], "source": [ - "supported_devices = fireopal.show_supported_devices(credentials=credentials)[\n", - " \"supported_devices\"\n", - "]\n", + "supported_devices = fireopal.show_supported_devices(credentials=credentials)[\"supported_devices\"]\n", "for name in supported_devices:\n", " print(name)" ] @@ -501,9 +499,7 @@ ], "source": [ "print(f\"Success probability: {100 * bitstring_results[0]['11111111111']:.2f}%\")\n", - "plot_bv_results(\n", - " bitstring_results[0], hidden_string=\"11111111111\", title=f\"Fire Opal ($n=11$)\"\n", - ")" + "plot_bv_results(bitstring_results[0], hidden_string=\"11111111111\", title=f\"Fire Opal ($n=11$)\")" ] }, { @@ -552,15 +548,11 @@ "circuit_qiskit = qiskit.QuantumCircuit.from_qasm_str(circuit_qasm)\n", "ibm_result = sampler.run(circuit_qiskit).result()\n", "ibm_probabilities = (\n", - " ibm_result.quasi_dists[0]\n", - " .nearest_probability_distribution()\n", - " .binary_probabilities(num_bits=11)\n", + " ibm_result.quasi_dists[0].nearest_probability_distribution().binary_probabilities(num_bits=11)\n", ")\n", "\n", "print(f\"Success probability: {100 * ibm_probabilities['11111111111']:.2f}%\")\n", - "plot_bv_results(\n", - " ibm_probabilities, hidden_string=\"11111111111\", title=f\"{backend_name} ($n=11$)\"\n", - ")" + "plot_bv_results(ibm_probabilities, hidden_string=\"11111111111\", title=f\"{backend_name} ($n=11$)\")" ] }, { diff --git a/qbraid_lab/gpu/cirq_VQE_cuQuantum.ipynb b/qbraid_lab/gpu/cirq_VQE_cuQuantum.ipynb index d2afd5b..591cbbf 100644 --- a/qbraid_lab/gpu/cirq_VQE_cuQuantum.ipynb +++ b/qbraid_lab/gpu/cirq_VQE_cuQuantum.ipynb @@ -444,9 +444,7 @@ "def energy_func(length, h, jr, jc):\n", " def energy(measurements):\n", " # Reshape measurement into array that matches grid shape.\n", - " meas_list_of_lists = [\n", - " measurements[i * length : (i + 1) * length] for i in range(length)\n", - " ]\n", + " meas_list_of_lists = [measurements[i * length : (i + 1) * length] for i in range(length)]\n", " # Convert true/false to +1/-1.\n", " pm_meas = 1 - 2 * np.array(meas_list_of_lists).astype(np.int32)\n", "\n", diff --git a/qbraid_lab/gpu/lightning_gpu_benchmark.ipynb b/qbraid_lab/gpu/lightning_gpu_benchmark.ipynb index 4bc5129..5853c9c 100644 --- a/qbraid_lab/gpu/lightning_gpu_benchmark.ipynb +++ b/qbraid_lab/gpu/lightning_gpu_benchmark.ipynb @@ -177,9 +177,7 @@ " qml.CNOT(wires=[i, (i + 1) % n_wires])\n", "\n", " # Measure all qubits\n", - " observables = [qml.PauliZ(n_wires - 1)] + [\n", - " qml.Identity(i) for i in range(n_wires - 1)\n", - " ]\n", + " observables = [qml.PauliZ(n_wires - 1)] + [qml.Identity(i) for i in range(n_wires - 1)]\n", " return qml.expval(qml.operation.Tensor(*observables))" ] }, diff --git a/qbraid_lab/quantum_jobs/aws_iqm_quantum_jobs.ipynb b/qbraid_lab/quantum_jobs/aws_iqm_quantum_jobs.ipynb index 200a5f7..0c76ab0 100644 --- a/qbraid_lab/quantum_jobs/aws_iqm_quantum_jobs.ipynb +++ b/qbraid_lab/quantum_jobs/aws_iqm_quantum_jobs.ipynb @@ -106,9 +106,7 @@ "\n", "# The IQM Garnet device\n", "device = AwsDevice(\"arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet\")\n", - "supported_gates = device.properties.action[\n", - " \"braket.ir.openqasm.program\"\n", - "].supportedOperations\n", + "supported_gates = device.properties.action[\"braket.ir.openqasm.program\"].supportedOperations\n", "# print the supported gate set\n", "print(\"Gate set supported by the IQM device:\\n\", supported_gates)" ] diff --git a/qbraid_qir/autoqasm_deutsch_jozsa.ipynb b/qbraid_qir/autoqasm_deutsch_jozsa.ipynb new file mode 100644 index 0000000..fbdf957 --- /dev/null +++ b/qbraid_qir/autoqasm_deutsch_jozsa.ipynb @@ -0,0 +1,323 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Deutsch-Jozsa Algorithm with Imperative Computation (AutoQASM)\n", + "\n", + "This notebook will introduce the Deutsch-Joszsa problem and solution. We then implement the quantum solution with AutoQASM, demonstrating it's success by submitting quantum jobs to qBraid's QIR simulator." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "### The Problem\n", + "We are given a hidden decision function $f: \\mathbb \\{0, 1\\}^n \\to \\{0, 1\\}$. For this problem, we assume any such $f$ is either \"balanced\" or \"constant\". \n", + "- Balanced: $f$ returns $0$'s on exactly $2^{n-1}$ of the possible inputs, and $1$'s on the other $2^{n-1}$.\n", + "- Constant: $f(x) = 0$ or $f(x) = 1$ for all $x \\in \\{0, 1\\}^n$. \n", + "\n", + "The Deutch-Jozsa problem is to determine, given a function $f$, to determine whether it is in fact balanced or constant." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Classical Deterministic Solution\n", + "\n", + "By doing a worst-case analysis on the problem, it is easy to see that we would require $2^{n-1} + 1$ calls to $f$ to solve this problem. There are probabilistic classical alternatives that use less calls." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Classical Probabilistic Solution\n", + "\n", + "Given that a function is balanced where the inputs are uniformly chosen to have output $0$ or $1$, there is a $\\dfrac{1}{2^{n-1}}$ probability that we actually have to query $f$ $2^{n-1}+1$ times. This hints at a probabilistic solution to the problem.\n", + "\n", + "The solution is the choose $k$ random inputs, from which we can derive $$P_{\\text{constant}}(k) = 1- \\frac{1}{2^{k-1}}.$$\n", + "\n", + "Basically, we can run the classical deterministic solution and just break whenever we have, say, $p$ probability of confidence." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Quantum Solution\n", + "\n", + "A quantum computer can solve the Deutsch-Jozsa problem with 100% confidence with only ***one*** call to $f$. The actual circuit has $n+1$ qubits ($n \\ket{0}$ 's and $1 \\ket{1}$) and is split into four main parts:\n", + "1. Preparing the quantum registers: The first $n$-qubit register are set to $\\ket{0}^{\\otimes n}$ and the second as $\\ket 1$: $$\\ket {\\psi_0} = \\ket 0 ^{\\otimes n} \\ket 1.$$\n", + "2. Applying a Hadamard gate to all qubits: $$\\ket{\\psi_{1}} = \\frac{1}{\\sqrt{2^{n+1}}} \\sum_{x=0}^{2^n-1} \\ket x (\\ket 0 - \\ket 1).$$\n", + "3. Appling the quantum oracle $U_f: \\ket x \\ket y \\mapsto \\ket x \\ket{y \\oplus f(x)}$: $$\\ket{\\psi_2} = \\frac{1}{\\sqrt{2^n+1}} \\sum_{x=0}^{2^n-1} (-1)^{f(x)}\\ket x (\\ket 0 - \\ket 1)$$\n", + "4. Applying a Hadamard gate to the first $n$ qubits: $$\\ket{\\psi_3} = \\frac{1}{2^n} \\sum_{y=0}^{2^n-1} \\left[\\sum_{x=0}^{2^n-1} (-1)^{f(x)} (-1)^{x\\cdot y}\\right] \\ket y $$\n", + "\n", + "Now, we just measure the first register. We see that: $$P(\\ket{0}^{\\otimes n}) = \\left| \\frac{1}{2^n} \\sum_{x=0}^{2^n - 1} (-1)^{f(x)} \\right|^2,$$\n", + "which is 1 *if and only if* $f$ is constant. This suffices to show correctness of our solution." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### The Oracle\n", + "**Constant Oracle**\n", + "\n", + "When a oracle is constant, it has no effect on the input qubits. So step 4 reverses step 2, giving us the same vector we had after step 1. \n", + "\n", + "**Balanced Oracle**\n", + "\n", + "Step 2 gives us an $x$ that is an equal superposition of all states in the $n$-qubit basis. A balanced oracle has a phase kickback that gives negative phase to exactly half of the states. The state after applying the oracle is orthogonal to the prior state, meaning applying $n$ Hadamard gates yields a state orthogonal to $\\ket{00\\ldots 0}$. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## AutoQASM Implementation\n", + "\n", + "We start by importing the relevant libraries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install qbraid \\\n", + " qbraid-qir \\\n", + " autoqasm \\\n", + " matplotlib --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import autoqasm as aq\n", + "import autoqasm.instructions as ins\n", + "\n", + "from qbraid.runtime import QbraidProvider\n", + "from qbraid.visualization import plot_histogram" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Constant Example\n", + "\n", + "For this example, we're gonna use a four qubit example. We start by identifying that the oracle is going to just be the identity, as a valid $U_f: \\ket x \\ket y \\mapsto \\ket x \\ket{y \\oplus 0} = \\ket x \\ket y$ is the identity mapping." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "n = 4" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def constant_f(x):\n", + " return 0\n", + "\n", + "\n", + "@aq.gate\n", + "def constant_oracle(q1: aq.Qubit, q2: aq.Qubit, q3: aq.Qubit, q4: aq.Qubit, q5: aq.Qubit):\n", + " pass\n", + "\n", + "\n", + "@aq.main(num_qubits=n + 1)\n", + "def deutch_jozsa_constant():\n", + " ins.x(4)\n", + " for i in range(n + 1):\n", + " ins.h(i)\n", + "\n", + " constant_oracle(*range(n + 1))\n", + "\n", + " for i in range(n + 1):\n", + " ins.h(i)\n", + "\n", + " for i in range(n):\n", + " ins.measure(i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## qBraid Instructions\n", + "\n", + "qBraid providers a QIR Simulator for quantum jobs. To demonstrate its usage, we'll be using it to simulate the Deutsch-Jozsa algorithm." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "provider = QbraidProvider()\n", + "\n", + "device = provider.get_device(\"qbraid_qir_simulator\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "job = device.run(deutch_jozsa_constant, shots=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAG9CAYAAAD0lWkWAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/PUlEQVR4nO3deXRU9f3/8de9E7IYyEJCNghJgKCAYBAQIm5IShDUIihSU0Wk4vEHWKUVsS4Va6Xi+bqgVmqr4AIVV1RQlKWCSGQJRpAt7AmESYCQTAJkkszM74/EmUmhKjGQwH0+zuGczvt+Zj6fedfceeUuE8Pj8XgEAABgYWZTLwAAAKCpEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlEYgAAIDlNWkgWrFiha677jolJCTIMAzNnz/fu626uloPPPCAunfvrtDQUCUkJOi2225TYWFhvdcoKSlRVlaWwsLCFBERobFjx6qioqLemA0bNujyyy9XcHCwEhMTNX369DPx9gAAwFmiSQPR0aNHddFFF+mll146YduxY8e0fv16PfLII1q/fr0++OADbdu2Tddff329cVlZWdq0aZMWL16sBQsWaMWKFRo3bpx3u8Ph0KBBg5SUlKScnBw9/fTTeuyxx/TKK6+c9vcHAADODkZz+eOuhmHoww8/1LBhw/7nmLVr1+qSSy7R3r171b59e23ZskVdu3bV2rVr1bt3b0nSokWLNGTIEO3bt08JCQl6+eWX9dBDD8lutyswMFCSNGXKFM2fP19bt249E28NAAA0cwFNvYBTUVZWJsMwFBERIUnKzs5WRESENwxJUkZGhkzT1OrVq3XDDTcoOztbV1xxhTcMSVJmZqaeeuopHTlyRJGRkSfM43Q65XQ6vY/dbrdKSkoUFRUlwzBO3xsEAACNxuPxqLy8XAkJCTLNHz8pdtYEosrKSj3wwAP6zW9+o7CwMEmS3W5XTExMvXEBAQFq3bq17Ha7d0xKSkq9MbGxsd5tJwtE06ZN09SpU0/H2wAAAGdYQUGB2rVr96NjzopAVF1drZEjR8rj8ejll18+7fM9+OCDmjRpkvdxWVmZ2rdvr4KCAm8YAwAAzZvD4VBiYqJatWr1k2ObfSD6IQzt3btXy5YtqxdI4uLiVFxcXG98TU2NSkpKFBcX5x1TVFRUb8wPj38Y89+CgoIUFBR0Qj0sLIxABADAWebnXO7SrL+H6IcwtH37di1ZskRRUVH1tqenp6u0tFQ5OTne2rJly+R2u9W3b1/vmBUrVqi6uto7ZvHixTr//PNPeroMAABYT5MGooqKCuXm5io3N1eStHv3buXm5io/P1/V1dW68cYbtW7dOs2ZM0cul0t2u112u11VVVWSpC5dumjw4MG68847tWbNGn399deaMGGCRo0apYSEBEnSLbfcosDAQI0dO1abNm3SvHnz9Pzzz9c7JQYAAKytSW+7//LLLzVgwIAT6qNHj9Zjjz12wsXQP/jPf/6jq666SlLtFzNOmDBBn3zyiUzT1IgRIzRjxgy1bNnSO37Dhg0aP3681q5dq+joaE2cOFEPPPDAz16nw+FQeHi4ysrKOGUGAMBZ4lQ+v5vN9xA1ZwQiAADOPqfy+d2sryECAAA4EwhEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAM4599xzj5KTk2UYhnJzc7317du369JLL1Xnzp3Vp08fbdq06RdvA3BuIBABOOfceOONWrlypZKSkurV77rrLo0bN055eXl64IEHdPvtt//ibQDODYbH4/E09SKaO4fDofDwcJWVlSksLKyplwPgZ0pOTtb8+fOVlpam4uJiderUSSUlJQoICJDH41F8fLxWrlypsLCwBm3r1KlTU79FAD/iVD6/OUIEwBIKCgoUHx+vgIAASZJhGGrfvr3y8/MbvA3AuYNABAAALC+gqRcAAGdCYmKiDhw4oJqaGu+pr/z8fLVv315hYWEN2gbg3MERIgCWEBMTo4svvlhvvfWWJOn9999Xu3bt1KlTpwZvA3Du4KLqn4GLqoGzy1133aWFCxfKbrcrKipKrVq10o4dO7Rt2zbdfvvtOnz4sMLCwjRr1ix1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mzRv3jw9//zzmjRpUhO9awAA0Nw06TVE69at04ABA7yPfwgpo0eP1uzZszV58mQdPXpU48aNU2lpqS677DItWrRIwcHB3ufMmTNHEyZM0MCBA2WapkaMGKEZM2Z4t4eHh+uLL77Q+PHj1atXL0VHR+vRRx+t911FAADA2prNXWbN2en+a/fcZQYAsLqmvsus2V5DBAAAcKYQiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOU160Dkcrn0yCOPKCUlRSEhIerYsaP+8pe/yOPxeMd4PB49+uijio+PV0hIiDIyMrR9+/Z6r1NSUqKsrCyFhYUpIiJCY8eOVUVFxZl+OwAAoJlq1oHoqaee0ssvv6wXX3xRW7Zs0VNPPaXp06frhRde8I6ZPn26ZsyYoZkzZ2r16tUKDQ1VZmamKisrvWOysrK0adMmLV68WAsWLNCKFSs0bty4pnhLAACgGTI8/odbmplrr71WsbGxevXVV721ESNGKCQkRG+99ZY8Ho8SEhL0hz/8QX/84x8lSWVlZYqNjdXs2bM1atQobdmyRV27dtXatWvVu3dvSdKiRYs0ZMgQ7du3TwkJCT+5DofDofDwcJWVlSksLKzR32fylIWN/poAAJxN9vxtaKO/5ql8fjfrI0SXXnqpli5dqry8PEnSd999p5UrV+qaa66RJO3evVt2u10ZGRne54SHh6tv377Kzs6WJGVnZysiIsIbhiQpIyNDpmlq9erVJ53X6XTK4XDU+wcAAM5dAU29gB8zZcoUORwOXXDBBbLZbHK5XPrrX/+qrKwsSZLdbpckxcbG1ntebGysd5vdbldMTEy97QEBAWrdurV3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Re+9956qqqqaelkAGhGBCAB+xPbt23XppZcqJCREmZmZ2rt3r6ZNm6bx48fr+PHjTb08AI2Eb6oGgB/x+OOPKzc3Vx988IGk2lNnM2bM0L///W+lpqbqtddeU3BwcBOvEsAvxREiAPgRxcXFKigo8D4OCAjQ+PHjdccdd2jXrl168skn5XK5mnCFABoDgQgATsLtdkuS0tLSZBiGNmzYoB8OqAcFBem2225Tenq6Fi5cqLKysqZcKoBGwCkzAPDj8XhkGIb3cWFhoS655BL17dtX//rXvxQZGekdU1paqujoaM2bN08jRoxowlUD+KUCmnoBANBcbNu2TXPmzFF+fr4uu+wy9evXTxdeeKHmz5+vAQMGaOLEiXr66acVHx8vqfZ6oh49eqh169ZNvHIAvxSBCABUe2v9pZdeqoyMDB04cEBbt27V1KlT9eqrr2rQoEH65JNPdP3116u4uFi/+c1v1KNHD7377rsqLCxUx44dm3r5AH4hTpkBsDyXy6Xbb79dHo9Hb731liQpNzdXL774ombPnq358+fr2muvVV5enn7/+99r165dqqmpUUhIiN5880317Nmzid8BgF+KI0QALM/tdqugoEDp6eneWlpamqZNm6bAwEDddNNN+uKLL3T55ZfrvffeU1lZmcrLy9WmTRtOlwHnCAIRAMtr0aKFLrzwQi1fvlxHjhxRZGSkJKlNmzZ68MEHVVxcrGnTpql79+6KiIhQaGhoE68YQGPjtnsAkHTFFVfo+PHjmjVrlsrLy731xMREXXfddfruu+/q1QGcWzhCBMBy9uzZo8WLF8s0TbVr106ZmZkaOXKkvvrqK/3jH/9QSEiIbr75Zu/psD59+ui8884jEAHnMAIRAEvZuHGjBgwYoNTUVB08eFBFRUW68cYbNWPGDL3wwgv63e9+p7///e/Ky8vThAkTFB4ertdff12maSo2Nraplw/gNOEuMwCWUVFRoUGDBql3796aMWOG7Ha7cnNzlZWVpZ49e2ru3LmKiYnR448/riVLlmjlypW6+OKLtX//fn366afcTQacwwhEACyjsrJS/fv31+TJk3XzzTd763l5eerfv7/69eunTz75RFLt3zBbv369WrVqpaSkJLVr166plg3gDOCiagCW4XK5VFRUpG3btnlr1dXV6ty5s5YuXar//Oc/mjp1qiQpJiZGgwcPVv/+/QlDgAUQiABYRmhoqCZNmqR//vOfWrBggaTaW+6rq6vVo0cPPfjgg/rss89UUlLi/eOuAKyBi6oBnLMOHDiggoICHTlyRBkZGbLZbBo+fLi++eYbTZ8+XYGBgRo0aJBatGghSYqOjpbD4VBwcLBMk98XASvhJx7AOWnDhg1KT0/XrbfeqptvvlndunXT22+/rbZt22ry5MkKDw/Xww8/rLfffltS7amzXbt2KSYmRi6Xq4lXD+BM46JqAOecgwcP6oorrtDw4cM1duxYBQcHa9KkSfr222+VlZWlBx54QFu3btXMmTP1r3/9S926dVNISIi2bdumZcuWKS0tranfAoAzjEAE4JyzefNmDR06VO+995569erlrU+ZMkULFizQmDFjNGnSJB07dkwbN27UkiVL1KZNGw0cOFCdOnVqwpUDaCpcQwTgnFNVVaXq6modO3ZMknT8+HGFhITob3/7m44fP64XXnhBv/rVr9SjRw/169dP/fr1a+IVA2hqHCECcE5wu93yeDyy2WySpMsvv1ymaWr58uWSJKfTqaCgIEm1f4qjU6dO+ve//91k6wXQvHBRNYCz3ubNm3XbbbcpMzNTd955p5YvX67nn39e+/fv18iRIyVJQUFBqqmpkVT7h1yPHj3alEsG0MwQiACc1bZt26ZLL71ULpdLffr00dq1a3X//ffrX//6l/7yl78oJydHN9xwg6qrq7230hcXFys0NFQ1NTXiIDkAiVNmAM5iHo9HDz/8sHbs2KF58+ZJksrLy/Xcc89pwYIF6tSpk0aOHKnJkydLkrp27arAwEAtXLhQ33zzjS688MKmXD6AZoSLqgGctQzDUGFhoex2u7fWqlUr3XvvvQoJCdEHH3ygvLw8rVu3Tn/96191+PBhBQcHa82aNeratWsTrhxAc8MRIgBnJY/HI8Mw9MILL2jevHl69dVXdf7553u3HzlyRJMnT9bGjRuVnZ0twzAk1V58zbdQA/hvBCIAZ7WdO3eqX79+uv766/X888+rZcuW3rBUUFCgpKQkLViwQEOGDJHkC1IA4I9TZgDOah07dtQ777yja665RiEhIXrssccUHR0tqfYPt/bo0UORkZHe8YQhACdDIAJw1hswYIDeffdd3XTTTTpw4IBGjhypHj166I033lBxcbESExObeokAmjlOmQE4Z6xfv16TJk3Snj17FBAQIJvNprfffls9e/Zs6qUBaOYIRADOKQ6HQyUlJSovL1d8fLz39BkA/BgCEQAAsDzuPQUAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJb3/wG54MAtD8ImNAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result = job.result()\n", + "\n", + "counts = result.measurement_counts()\n", + "\n", + "plot_histogram(counts)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, the algorithm returns $\\ket{00000}$ 100% of the time, implying that our $f$ is constant. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we consider a balanced $f$. The f we will use is given by $$f(x) = \\begin{cases} 0 & x \\in [0, 7] \\\\ 1 & x \\in [8, 15]\\end{cases}.$$\n", + "\n", + "To construct $U_f$ that suffices $\\ket x \\ket y \\mapsto \\ket x \\ket{y \\oplus f(x)}$, we consider when $f(x) = 1$, which is exactly when the most significant bit (MSB) is also equal to 1. As such, our oracle just uses a controlled-NOT gate where the control qubit is the MSB of $x$ adn the target bit is $y$. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def balanced_f(x):\n", + " if x in range(0, 2**n / 2):\n", + " return 0\n", + " return 1\n", + "\n", + "\n", + "@aq.gate\n", + "def balanced_oracle(q0: aq.Qubit, q1: aq.Qubit, q2: aq.Qubit, q3: aq.Qubit, q4: aq.Qubit):\n", + " ins.cnot(q3, q4)\n", + "\n", + "\n", + "@aq.main(num_qubits=n + 1)\n", + "def deutch_jozsa_balanced():\n", + " ins.x(4)\n", + " for i in range(n + 1):\n", + " ins.h(i)\n", + "\n", + " balanced_oracle(*range(n + 1))\n", + "\n", + " for i in range(n + 1):\n", + " ins.h(i)\n", + "\n", + " for i in range(n):\n", + " ins.measure(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "job_bal = device.run(deutch_jozsa_balanced, shots=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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7nd3mYoLka6N983zZb6pSrd0k18vVhUaynUYusOvF1uOGFpz0NRtbVwKrXk35Vhe92P5gQMHlJ+f76116dJFTqfTe1JEktq3b6+QkBBt3LjRW0tMTFR8fLzWrl3rrUVHR6tNmza13o9/SqO+ZPbuu+/qoYce0vPPP6/OnTsrOztbkyZN0gsvvKAxY8Zo9erV6tOnjwoKChQfH+993siRI2UYhubPn69nn31Wc+fO1fbt22u9dkxMjKZNm6Z77733lHmdTqecTqf3scPhUGJiIpfMAAA4Sxr6klmjPkP00EMPacqUKRo1apSk6rS4d+9eTZ8+XWPGjFFcXJwkqbCwsFYgKiwsVNeuXSVJcXFxKioqqvW6J06cUHFxsff5/y4oKEhBQUFnYY8AAEBj1KjvITp27JhMs/YSbTab3O7q03QpKSmKi4vT0qVLvdsdDofWrFmj1NRUSVJqaqpKSkpqXbJatmyZ3G63evXqdQ72AgAANHaN+gzRDTfcoGeeeUatW7dW586d9d133+mFF17QXXfdJUkyDEOTJk3S008/rfbt2yslJUWPP/64EhISNGzYMElSx44dNXjwYN19992aNWuWqqqqNHHiRI0aNepnfcIMAABc+Bp1IHrllVf0+OOP6//9v/+noqIiJSQk6J577tHUqVO9Yx5++GEdPXpU48ePV0lJifr27atFixYpODjYO+add97RxIkTNXDgQJmmqREjRmjmzJkNsUsAAKARatQ3VTcWfA8RAABnV0PfVN2o7yECAAA4FwhEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8uoUiDZs2KBNmzZ5H3/66acaNmyYfv/736uysrLeFgcAAHAu1CkQ3XPPPcrJyZEk7dq1S6NGjdJFF12k999/Xw8//HC9LhAAAOBsq1MgysnJUdeuXSVJ77//vvr166d58+Zpzpw5+vDDD+tzfQAAAGddnQKRx+OR2+2WJC1Z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vbXTpm5RbnWL8s397i5TcSHStfG+eb7MN1Xplm7y68WqQkO5DkN3+PViyxFDaw6auq2NS6E176Ycy+t+LD9w4IDy8/O9tS5dusjpdConJ8dba9++vUJCQrRx40ZvLTExUfHx8Vq7dq23Fh0drTZt2tR6P/4pdbpk9sADD9R6XFVVpezsbG3evFljxozRyy+/fKYveVqBgYHq0aOHVq9e7a3df//9WrdunTIzM7V69Wr16dNHBQUFio+P944ZOXKkDMPQ/Pnz9eyzz2ru3Lnavn17rdeOiYnRtGnTdO+9954yr9PplNPp9D52OBxKTEzkkhkAAGdJQ18yq9MZohdffPG09SeeeKJeP70VHx+vTp061ap17NhRH374oSQpLi5OklRYWFgrEBUWFnpv+o6Li1NRUVGt1zhx4oSKi4u9z/93QUFBCgoKqq/dAAAAjVy93kP0m9/8pl7/jlmfPn1OObOTk5OjpKQkSVJKSori4uK0dOlS73aHw6E1a9YoNTVVkpSamqqSkpJal6yWLVsmt9utXr161dtaAQDA+avOf9z1dDIzM70fda8PDzzwgK666io9++yzGjlypNauXas33nhDb7zxhqTqj/hPmjRJTz/9tNq3b+/92H1CQoKGDRsmqfqM0uDBg3X33Xdr1qxZqqqq0sSJEzVq1Kif9QkzAABw4atTIBo+fHitxx6PRwcOHND69ev1+OOP18vCJKlnz576+OOP9eijj+rJJ59USkqKXnrpJWVkZHjHPPzwwzp69KjGjx+vkpIS9e3bV4sWLaoVzN555x1NnDhRAwcOlGmaGjFihGbOnFlv6wQAAOe3Ot1UPXbs2FqPTdNUixYtNGDAAA0aNKjeFtdY8D1EAACcXeflTdWzZ8+u08IAAAAao190D1FWVpa2bdsmSercubO6detWL4sCAAA4l+oUiIqKijRq1Ch98803ioyMlCSVlJSof//+evfdd9WiRYv6XCMAAMBZVaeP3d93330qKyvTli1bVFxcrOLiYm3evFkOh0P3339/fa8RAADgrKrTGaJFixZpyZIl6tixo7fWqVMnvfbaaxfkTdUAAODCVqczRG63W02aNDml3qRJE7nd7tM8AwAAoPGqUyAaMGCAfvvb36qgoMBb279/vx544AENHDiw3hYHAABwLtQpEL366qtyOBxKTk5W27Zt1bZtW6WkpMjhcOiVV16p7zUCAACcVXW6hygxMVEbNmzQkiVL9MMPP0iq/hMZaWlp9bo4AACAc+GMzhAtW7ZMnTp1ksPhkGEY+tWvfqX77rtP9913n3r27KnOnTvrX//619laKwAAwFlxRoHopZde0t13333ar7+OiIjQPffcoxdeeKHeFgcAAHAunFEg+v777zV48OD/uH3QoEHKysr6xYsCAAA4l84oEBUWFp724/YnBQQE6ODBg794UQAAAOfSGQWili1bavPmzf9x+8aNGxUfH/+LFwUAAHAunVEgGjJkiB5//HFVVFScsu348eP64x//qOuvv77eFgcAAHAunNHH7h977DF99NFH6tChgyZOnKiLL75YkvTDDz/otddek8vl0h/+8IezslAAAICz5YwCUWxsrFavXq17771Xjz76qDwejyTJMAylp6frtddeU2xs7FlZKAAAwNlyxl/MmJSUpC+++EJHjhzRzp075fF41L59ezVr1uxsrA8AAOCsq9M3VUtSs2bN1LNnz/pcCwAAQIOo098yAwAAuJAQiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOWdV4HoT3/6kwzD0KRJk7y1iooKTZgwQVFRUQoLC9OIESNUWFhY63l5eXkaOnSoLrroIsXExOihhx7SiRMnzvHqAQBAY3XeBKJ169bpL3/5iy677LJa9QceeECff/653n//fS1fvlwFBQUaPny4d7vL5dLQoUNVWVmp1atXa+7cuZozZ46mTp16rncBAAA0UudFICovL1dGRob++te/qlmzZt56aWmp/v73v+uFF17QgAED1L17d82ePVurV6/Wt99+K0n6+uuvtXXrVr399tvq2rWrrrvuOj311FN67bXXVFlZ2VC7BAAAGpHzIhBNmDBBQ4cOVVpaWq16VlaWqqqqatUvueQStW7dWpmZmZKkzMxMdenSRbGxsd4x6enpcjgc2rJly2nnczqdcjgctf4BAIALV0BDL+CnvPvuu9qwYYPWrVt3yja73a7AwEBFRkbWqsfGxsput3vH+Iehk9tPbjud6dOna9q0aafU169fr7CwMElS165dVVZWptzcXO/2Sy65RDabrVbQSk5OVlRUlLKysmrNn5SUpOzsbFVWVuquDi7tO2ro6/2mBrdyKeGi6nFlVdL7u21KjXGrY6TH+/zZOaY6RnrUO8ZX+2iPqdAAKb2V21tbWmDqcIU0so2vlnXI0PfFpu5s75JpVNd2OAz9y27q5iSXmgVV14oqpAV5Ng1IcCs5rHoep1t6Z6dN3aPdury5b+55uaZahkrXxPnmWZhvyu2Rbmjtq60sNLS7zNDodr7apiOG1h009eu2LoXYqmt55YaWFJgakuhSXEh1rbRK+nC3TX1i3bo4wjf3P3JsurSZW1e28NU+3GOqaRNpUEvfPEv2myqplG5J8dXWHTS06YipsR1cqmmFckoNrSw0NTzZpcjA6lrhcWlhvk0DE9xKqulFhUual2tTj2i3LvPrxTs7TSWGedQvzldbkFf9e8f1fr1YYTeUX24ow68XG4sNrT9k6va2LgXX9GJvuaGlBaaGJroUW9OLkkrpoz029Y11q0NNLzySZufY1KWZWz39evHBblORgVKaXy++3m+qrEoakeyrrT1oaPMRU3d1cHlr20sNrSo0NSLFpYgm1TX7cemLfJvSEtxqXdOL4y7pn7k29WzhVpdmvrnf2mkqpalHfWN9tc/zTJmGNDTRN/dyu6n9R6Xb2/pq3xcbyjpkKqOdS0E1v7btKTe0rMDU9a1digmurh1xSh/vtenqOLfah1fP4/ZIc3bYdHlzt7pH++Z+b5epqGBpYIJvnq/2mTp6Qhru14tviwxtKzE0toOvtq3EUGaRqVtTXGpa04uCY9KifTYNaulWq9DqeY6ekObvsqlXC7c6+/XizR2m2oZ71MevF5/uNRVoStf59eKbA6bsx6VRfj+z3x029N1hU6PbudSkphe7ygx9c8DUja1diq7pxWGn9Olem66Jc6ttTS9OeKQ3d9jUtblbV/j1Yv4uUy2CpQF+vVi0z1SFSxqW5KtlFhnaXmrozva+2tYSQ98WmRqZ4lJYTS/2HzP01T5T6a3canlR9TzlVdJ7u23qHeNWJ7/j15wdpi6O8CjV7/j1yV5TwTZpsN/xa1mBqYMV0m1+vdhwyFB2sak72rsUUPNDm+swtNxu6qYkl6Jqjl+HKqTP8my6Nt6tNk2r56lyS2/ttKlblFvdonxzv7vLVFyIdG28b54v801VuqWb/HqxqtBQrsPQHX692HLE0JqDpm5r41Jozbspx/K6H8sPHDig/Px8b61Lly5yOp3Kycnx1tq3b6+QkBBt3LjRW0tMTFR8fLzWrl3rrUVHR6tNmzb/8cTH6Rgej8fz08MaRn5+vnr06KHFixd77x269tpr1bVrV7300kuaN2+exo4dK6fTWet5V155pfr376/nnntO48eP1969e/XVV195tx87dkyhoaH64osvdN11150yr9PprPWaDodDiYmJKi0tVXh4eL3vZ/KUhfX+mgAAnE/2/Glovb+mw+FQRETEz3r/btSXzLKyslRUVKQrrrhCAQEBCggI0PLlyzVz5kwFBAQoNjZWlZWVKikpqfW8wsJCxcXFSZLi4uJO+dTZyccnx/y7oKAghYeH1/oHAAAuXI06EA0cOFCbNm1Sdna291+PHj2UkZHh/d9NmjTR0qVLvc/Zvn278vLylJqaKklKTU3Vpk2bVFRU5B2zePFihYeHq1OnTud8nwAAQOPTqO8hatq0qS699NJatdDQUEVFRXnr48aN0+TJk9W8eXOFh4frvvvuU2pqqnr37i1JGjRokDp16qTRo0drxowZstvteuyxxzRhwgQFBQWd830CAACNT6MORD/Hiy++KNM0NWLECDmdTqWnp+vPf/6zd7vNZtOCBQt07733KjU1VaGhoRozZoyefPLJBlw1AABoTBr1TdWNxZnclFUX3FQNALA6bqoGAABoYAQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQi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7B1rs9m0YMEC3XvvvUpNTVVoaKjGjBmjJ5988lztBgAAaOTOm5uqGxLfQwQAwNnV0DdVN+p7iAAAAM4FAhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8SwWi1157TcnJyQoODlavXr20du3ahl4SAABoBCwTiObPn6/Jkyfrj3/8ozZs2KDLL79c6enpKioqauilAQCABhbQ0As4V1544QXdfffdGjt2rCRp1qxZWrhwof7xj39oypQptcY6nU45nU7v49LSUkmSw+E4K2tzO4+dldcFAOB8cTbeY0++psfj+cmxlghElZWVysrK0qOPPuqtmaaptLQ0ZWZmnjJ++vTpmjZt2in1xMTEs7pOAACsKuKls/faZWVlioiI+NExlghEhw4dksvlUmxsbK16bGysfvjhh1PGP/roo5o8ebL3sdvtVnFxsaKiomQYxllfL4Bzx+FwKDExUfn5+QoPD2/o5QCoRx6PR2VlZUpISPjJsZYIRGcqKChIQUFBtWqRkZENsxgA50R4eDiBCLgA/dSZoZMscVN1dHS0bDabCgsLa9ULCwsVFxfXQKsCAACNhSUCUWBgoLp3766lS5d6a263W0uXLlVqamoDrgwAADQGlrlkNnnyZI0ZM0Y9evTQlVdeqZdeeklHjx71fuoMgDUFBQXpj3/84ymXyQFYi+H5OZ9Fu0C8+uqrev7552W329W1a1fNnDlTvXr1auhlAQCABmapQAQAAHA6lriHCAAA4McQiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiADgZ6ioqFBZWVmtmtvtbqDVAKhvBCIA+AmbN2/WTTfd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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result_bal = job_bal.result()\n", + "\n", + "counts_bal = result_bal.measurement_counts()\n", + "\n", + "plot_histogram(counts_bal)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see here that the probability of measuring $\\ket{00000}$ is 0. This correctly predicts that our $f$ is balanced." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qir", + "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.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qbraid_qir/microsoft_resource_estimatation.ipynb b/qbraid_qir/microsoft_resource_estimatation.ipynb new file mode 100644 index 0000000..11ce745 --- /dev/null +++ b/qbraid_qir/microsoft_resource_estimatation.ipynb @@ -0,0 +1,1324 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hidden linear function problem: resource estimation example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install qbraid-qir \\\n", + " cirq-core \\\n", + " numpy \\\n", + " azure-quantum \\\n", + " 'azure-quantum[qiskit]' \\\n", + " 'qiskit<1.0.0'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from typing import List, Tuple, Any\n", + "\n", + "import cirq\n", + "import numpy as np\n", + "from azure.quantum import Workspace\n", + "from azure.quantum.qiskit import AzureQuantumProvider\n", + "from azure.quantum.qiskit.job import AzureQuantumJob\n", + "from qbraid_qir.cirq import cirq_to_qir\n", + "from qiskit.tools.monitor import job_monitor" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "Class for defining the Hidden Linear Function Problem. More information about the problem can be found here: https://quantumai.google/cirq/experiments/hidden_linear_function" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class HiddenLinearFunctionProblem:\n", + " \"\"\"\n", + " Instance of Hidden Linear Function problem.\n", + "\n", + " The problem is defined by a matrix A and a vector b, which are\n", + " the coefficients of a quadratic form, in which a linear function\n", + " is \"hidden\". The goal is to find binary vectors `z` that solve the\n", + " problem defined by the quadratic form.\n", + "\n", + " Attributes:\n", + " A (np.ndarray): Coefficient matrix for the quadratic form.\n", + " b (np.ndarray): Coefficient vector for the quadratic form.\n", + " n (int): Dimensionality of the problem, derived from A's shape.\n", + " L (list of np.ndarray): List of binary vectors in the subspace L_q,\n", + " to which the domain of the quadratic form is restricted.\n", + " all_zs (list of np.ndarray): All binary vectors `z` that are solutions to the problem.\n", + "\n", + " Raises:\n", + " AssertionError: If A is not an upper triangular matrix, or if b's shape\n", + " does not match the expected (n,).\n", + " \"\"\"\n", + "\n", + " def __init__(self, A: np.ndarray, b: np.ndarray):\n", + " \"\"\"\n", + " Initializes the Hidden Linear Function problem with matrix A and vector b.\n", + "\n", + " Args:\n", + " A (np.ndarray): Coefficient matrix for the quadratic form, must be upper triangular.\n", + " b (np.ndarray): Coefficient vector for the quadratic form.\n", + " \"\"\"\n", + " self.n = A.shape[0]\n", + " assert A.shape == (self.n, self.n)\n", + " assert b.shape == (self.n,)\n", + " for i in range(self.n):\n", + " for j in range(i + 1):\n", + " if A[i][j] != 0: # A[i][j] == 1 iff i < j\n", + " raise ValueError(\"A must be an upper triangular matrix\")\n", + "\n", + " self.A = A\n", + " self.b = b\n", + " self.L = None\n", + " self.all_zs = None\n", + "\n", + " def q(self, x: np.ndarray) -> int:\n", + " \"\"\"\n", + " Computes the action of the quadratic form on a binary vector (modulo 4).\n", + "\n", + " Args:\n", + " x (np.ndarray): A binary vector on which the quadratic form acts.\n", + "\n", + " Returns:\n", + " int: The result of the quadratic form acting on `x`, modulo 4.\n", + "\n", + " Raises:\n", + " ValueError: If the shape of `x` does not match the expected (n,).\n", + " \"\"\"\n", + " if x.shape == (self.n,):\n", + " raise ValueError(\"x must be a binary vector of length n\")\n", + " return (2 * (x @ self.A @ x) + (self.b @ x)) % 4\n", + "\n", + " def bruteforce_solve(self) -> None:\n", + " \"\"\"\n", + " Finds all binary vectors `z` which are solutions to the problem by brute force.\n", + "\n", + " This method updates the `L` attribute with vectors in the subspace L_q and\n", + " the `all_zs` attribute with all solution vectors `z`.\n", + "\n", + " Raises:\n", + " AssertionError: If called before `q` has been properly defined.\n", + " \"\"\"\n", + " # All binary vectors of length `n`.\n", + " all_vectors = [np.array([(m >> i) % 2 for i in range(self.n)]) for m in range(2**self.n)]\n", + "\n", + " def vector_in_L(x):\n", + " for y in all_vectors:\n", + " if self.q((x + y) % 2) != (self.q(x) + self.q(y)) % 4:\n", + " return False\n", + " return True\n", + "\n", + " self.L = [x for x in all_vectors if vector_in_L(x)]\n", + " self.all_zs = [z for z in self.L if self.is_z(z)]\n", + "\n", + " def is_z(self, z: np.ndarray) -> bool:\n", + " \"\"\"\n", + " Checks whether a given vector `z` is a solution to the problem.\n", + "\n", + " Args:\n", + " z (np.ndarray): The binary vector to check.\n", + "\n", + " Returns:\n", + " bool: True if `z` is a solution, False otherwise.\n", + "\n", + " Raises:\n", + " ValueError: If `z`'s shape does not match the expected (n,)\n", + " RuntimeError: If `L` has not been computed yet.\n", + " \"\"\"\n", + " if z.shape == (self.n,):\n", + " raise ValueError(\"z must be a binary vector of length n\")\n", + "\n", + " if self.L is None:\n", + " raise RuntimeError(\"L has not been computed yet, it must be\")\n", + "\n", + " for x in self.L:\n", + " if self.q(x) != 2 * ((z @ x) % 2):\n", + " return False\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "Example problem which is hard classically" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "A = np.array(\n", + " [\n", + " [0, 1, 1, 0, 0, 1, 0, 0, 1, 1],\n", + " [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],\n", + " [0, 0, 0, 0, 0, 0, 1, 1, 0, 1],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 1, 0],\n", + " [0, 0, 0, 0, 0, 1, 0, 0, 0, 1],\n", + " [0, 0, 0, 0, 0, 0, 1, 1, 0, 0],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 1, 1],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", + " ]\n", + ")\n", + "b = np.array([0, 0, 0, 0, 1, 1, 1, 0, 0, 1])\n", + "problem_10_64 = HiddenLinearFunctionProblem(A, b)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def edge_coloring(A: np.ndarray) -> List[List[Tuple[int, int]]]:\n", + " \"\"\"Solves the edge coloring problem for a given graph represented by its adjacency matrix.\n", + "\n", + " This function attempts to find an edge coloring of the graph such that no two edges sharing\n", + " a common vertex have the same color. The goal is to minimize the number of colors used.\n", + "\n", + " Args:\n", + " A (np.ndarray): The adjacency matrix of the graph, where `A[i, j] == 1` indicates an edge\n", + " between vertices `i` and `j`, and `A[i, j] == 0` indicates no edge.\n", + "\n", + " Returns:\n", + " List[List[Tuple[int, int]]]: A list of edge groups, where each group contains edges (as tuples\n", + " of vertices `(i, j)`) that can be assigned the same color without\n", + " violating the coloring constraints. Edges in the same group do not\n", + " share a common vertex.\n", + " \"\"\"\n", + " A = np.copy(A)\n", + " n = A.shape[0]\n", + " ans: List[List[Tuple[int, int]]] = []\n", + " while np.max(A) != 0:\n", + " edges_group: List[Tuple[int, int]] = []\n", + " used = np.zeros(n, dtype=bool)\n", + " for i in range(n):\n", + " for j in range(i + 1, n): # Adjusted to avoid duplication and ensure i < j\n", + " if A[i][j] == 1 and not used[i] and not used[j]:\n", + " edges_group.append((i, j))\n", + " A[i][j] = A[j][i] = 0 # Ensure the edge is removed from both [i, j] and [j, i]\n", + " used[i] = used[j] = True\n", + " ans.append(edges_group)\n", + " return ans" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_circuit_for_problem(problem: HiddenLinearFunctionProblem) -> cirq.Circuit:\n", + " \"\"\"\n", + " Generates a quantum circuit using Cirq that solves an instance of the Hidden Linear Function problem.\n", + "\n", + " The generated circuit includes Hadamard gates to create an equal superposition of all states, controlled-Z\n", + " gates to encode the matrix A of the problem, S gates to encode the vector b, another set of Hadamard gates,\n", + " and finally measurement gates.\n", + "\n", + " Args:\n", + " problem (HiddenLinearFunctionProblem): An instance of the Hidden Linear Function problem, defined by\n", + " a symmetric binary matrix A and a binary vector b.\n", + "\n", + " Returns:\n", + " cirq.Circuit: The quantum circuit designed to solve the given instance of the Hidden Linear Function\n", + " problem. The circuit applies a series of quantum gates to qubits arranged in a line\n", + " and measures each qubit at the end.\n", + " \"\"\"\n", + "\n", + " qubits = cirq.LineQubit.range(problem.n)\n", + " circuit = cirq.Circuit()\n", + "\n", + " # Hadamard gates at the beginning (creating equal superposition of all states).\n", + " circuit += cirq.Moment([cirq.H(q) for q in qubits])\n", + "\n", + " # Controlled-Z gates encoding the matrix A.\n", + " for layer in edge_coloring(problem.A):\n", + " for i, j in layer:\n", + " circuit += cirq.CZ(qubits[i], qubits[j])\n", + "\n", + " # S gates encoding the vector b.\n", + " circuit += cirq.Moment([cirq.S.on(qubits[i]) for i in range(problem.n) if problem.b[i] == 1])\n", + "\n", + " # Hadamard gates at the end.\n", + " circuit += cirq.Moment([cirq.H(q) for q in qubits])\n", + "\n", + " # Measurements.\n", + " circuit += cirq.Moment([cirq.measure(qubits[i], key=str(i)) for i in range(problem.n)])\n", + "\n", + " return circuit" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "Instatiating the AzureQuantumProvider with resource information" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "workspace = Workspace(\n", + " resource_id=\"\", # Your resource_id\n", + " location=\"westus\", # Your workspace location (for example, \"westus\")\n", + ")\n", + "provider = AzureQuantumProvider(workspace)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def resource_estimation_job_from_qir(\n", + " provider: AzureQuantumProvider, bitcode: bytes, **kwargs: Any\n", + ") -> AzureQuantumJob:\n", + " \"\"\"\n", + " Creates a resource estimation job from QIR bitcode using an Azure Quantum Provider.\n", + "\n", + " Args:\n", + " provider (AzureQuantumProvider): The Azure Quantum Provider through which the job\n", + " will be submitted.\n", + " bitcode (bytes): The QIR bitcode that defines the quantum operation for which\n", + " resources are to be estimated.\n", + " **kwargs (Any): Additional keyword arguments for job configuration. This may include\n", + " 'name' for the job name and other backend-specific settings.\n", + "\n", + " Returns:\n", + " AzureQuantumJob: The initialized Azure Quantum job object ready for submission.\n", + " \"\"\"\n", + "\n", + " # Find the Resource Estimator target from the provider\n", + " backend = provider.get_backend(\"microsoft.estimator\")\n", + "\n", + " # Job name handling via keyword arguments\n", + " name = kwargs.pop(\"name\", \"QIR job\")\n", + "\n", + " # Extract job-specific arguments from the backend's configuration\n", + " config = backend.configuration()\n", + " blob_name = config.azure[\"blob_name\"]\n", + " content_type = config.azure[\"content_type\"]\n", + " provider_id = config.azure[\"provider_id\"]\n", + " output_data_format = config.azure[\"output_data_format\"]\n", + "\n", + " # Create and return the Azure Quantum job object\n", + " return AzureQuantumJob(\n", + " backend=backend,\n", + " target=backend.name(),\n", + " name=name,\n", + " input_data=bitcode,\n", + " blob_name=blob_name,\n", + " content_type=content_type,\n", + " provider_id=provider_id,\n", + " input_data_format=\"qir.v1\",\n", + " output_data_format=output_data_format,\n", + " input_params=kwargs,\n", + " metadata={},\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "Converting the Cirq circuit to QIR and running resource estimation" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " ┌───┐ ┌──┐ ┌───┐ ┌───┐ ┌───┐\n", + "0: ───H────@───────@──────@───────@───────@──────────────────────H───M('0')───\n", + " │ │ │ │ │\n", + "1: ───H────@───────┼@─────┼@──────┼@──────┼@─────@───@───@───────H───M('1')───\n", + " ││ ││ ││ ││ │ │ │\n", + "2: ───H────@───────@┼─────┼┼@─────┼┼@─────┼┼─────┼───┼───┼───────H───M('2')───\n", + " │ │ │││ │││ ││ │ │ │\n", + "3: ───H────┼@───────@─────┼┼┼─────┼┼┼─────┼┼─────┼───┼───┼───────H───M('3')───\n", + " ││ │││ │││ ││ │ │ │\n", + "4: ───H────┼┼@─────@──────┼@┼─────┼┼┼─────┼┼─────┼───┼───┼───S───H───M('4')───\n", + " │││ │ │ │ │││ ││ │ │ │\n", + "5: ───H────┼┼@─────┼@─────@─┼─────┼@┼─────┼┼@────┼───┼───┼───S───H───M('5')───\n", + " ││ ││ │ │ │ │││ │ │ │\n", + "6: ───H────@┼──────┼@─────@─┼─────┼─┼─────┼@┼────┼───┼───┼───S───H───M('6')───\n", + " │ │ │ │ │ │ │ │ │ │ │\n", + "7: ───H────@┼──────┼@─────┼─@─────┼─┼─────┼─@────@───┼───┼───────H───M('7')───\n", + " ││ ││ │ │ │ │ │ │\n", + "8: ───H────┼@──────┼@─────┼───────@─┼─────┼──────────@───┼───────H───M('8')───\n", + " │ │ │ │ │ │\n", + "9: ───H────@───────@──────@─────────@─────@──────────────@───S───H───M('9')───\n", + " └───┘ └──┘ └───┘ └───┘ └───┘\n" + ] + } + ], + "source": [ + "problem_circuit = generate_circuit_for_problem(problem_10_64)\n", + "\n", + "print(problem_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Job Status: job has successfully run\n" + ] + } + ], + "source": [ + "module = cirq_to_qir(problem_circuit, record_output=False, name=\"problem_module\")\n", + "\n", + "job = resource_estimation_job_from_qir(provider, module.bitcode, errorBudget=0.05)\n", + "\n", + "job_monitor(job)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " Physical resource estimates\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Runtime20 microsecs\n", + " Total runtime\n", + "
\n", + "

This is a runtime estimate for the execution time of the algorithm. In general, the execution time corresponds to the duration of one logical cycle (2,000 nanosecs) multiplied by the 10 logical cycles to run the algorithm. If however the duration of a single T factory (here: 0 nanosecs) is larger than the algorithm runtime, we extend the number of logical cycles artificially in order to exceed the runtime of a single T factory.

\n", + "
rQOPS15.00M\n", + " Reliable quantum operations per second\n", + "
\n", + "

The value is computed as the number of logical qubits after layout (30) (with a logical error rate of 1.67e-4) multiplied by the clock frequency (500,000.00), which is the number of logical cycles per second.

\n", + "
Physical qubits1.50k\n", + " Number of physical qubits\n", + "
\n", + "

This value represents the total number of physical qubits, which is the sum of 1,500 physical qubits to implement the algorithm logic, and 0 physical qubits to execute the T factories that are responsible to produce the T states that are consumed by the algorithm.

\n", + "
\n", + "
\n", + " \n", + " Resource estimates breakdown\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Logical algorithmic qubits30\n", + " Number of logical qubits for the algorithm after layout\n", + "
\n", + "

Laying out the logical qubits in the presence of nearest-neighbor constraints requires additional logical qubits. In particular, to layout the $Q_{\\rm alg} = 10$ logical qubits in the input algorithm, we require in total $2 \\cdot Q_{\\rm alg} + \\lceil \\sqrt{8 \\cdot Q_{\\rm alg}}\\rceil + 1 = 30$ logical qubits.

\n", + "
Algorithmic depth10\n", + " Number of logical cycles for the algorithm\n", + "
\n", + "

To execute the algorithm using Parallel Synthesis Sequential Pauli Computation (PSSPC), operations are scheduled in terms of multi-qubit Pauli measurements, for which assume an execution time of one logical cycle. Based on the input algorithm, we require one multi-qubit measurement for the 10 single-qubit measurements, the 0 arbitrary single-qubit rotations, and the 0 T gates, three multi-qubit measurements for each of the 0 CCZ and 0 CCiX gates in the input program, as well as No rotations in algorithm multi-qubit measurements for each of the 0 non-Clifford layers in which there is at least one single-qubit rotation with an arbitrary angle rotation.

\n", + "
Logical depth10\n", + " Number of logical cycles performed\n", + "
\n", + "

This number is usually equal to the logical depth of the algorithm, which is 10. However, in the case in which a single T factory is slower than the execution time of the algorithm, we adjust the logical cycle depth to exceed the T factory's execution time.

\n", + "
Clock frequency500.00k\n", + " Number of logical cycles per second\n", + "
\n", + "

This is the number of logical cycles that can be performed within one second. The logical cycle time is 2 microsecs.

\n", + "
Number of T states0\n", + " Number of T states consumed by the algorithm\n", + "
\n", + "

To execute the algorithm, we require one T state for each of the 0 T gates, four T states for each of the 0 CCZ and 0 CCiX gates, as well as No rotations in algorithm for each of the 0 single-qubit rotation gates with arbitrary angle rotation.

\n", + "
Number of T factories0\n", + " Number of T factories capable of producing the demanded 0 T states during the algorithm's runtime\n", + "
\n", + "

The total number of T factories 0 that are executed in parallel is computed as $\\left\\lceil\\dfrac{\\text{T states}\\cdot\\text{T factory duration}}{\\text{T states per T factory}\\cdot\\text{algorithm runtime}}\\right\\rceil = \\left\\lceil\\dfrac{0 \\cdot 0\\;\\text{ns}}{0 \\cdot 20,000\\;\\text{ns}}\\right\\rceil$

\n", + "
Number of T factory invocations0\n", + " Number of times all T factories are invoked\n", + "
\n", + "

In order to prepare the 0 T states, the 0 copies of the T factory are repeatedly invoked 0 times.

\n", + "
Physical algorithmic qubits1.50k\n", + " Number of physical qubits for the algorithm after layout\n", + "
\n", + "

The 1,500 are the product of the 30 logical qubits after layout and the 50 physical qubits that encode a single logical qubit.

\n", + "
Physical T factory qubits0\n", + " Number of physical qubits for the T factories\n", + "
\n", + "

Each T factory requires 0 physical qubits and we run 0 in parallel, therefore we need $0 = 0 \\cdot 0$ qubits.

\n", + "
Required logical qubit error rate1.67e-4\n", + " The minimum logical qubit error rate required to run the algorithm within the error budget\n", + "
\n", + "

The minimum logical qubit error rate is obtained by dividing the logical error probability 5.00e-2 by the product of 30 logical qubits and the total cycle count 10.

\n", + "
Required logical T state error rateNo T states in algorithm\n", + " The minimum T state error rate required for distilled T states\n", + "
\n", + "

The minimum T state error rate is obtained by dividing the T distillation error probability 0.00e0 by the total number of T states 0.

\n", + "
Number of T states per rotationNo rotations in algorithm\n", + " Number of T states to implement a rotation with an arbitrary angle\n", + "
\n", + "

The number of T states to implement a rotation with an arbitrary angle is $\\lceil 0.53 \\log_2(0 / 0) + 5.3\\rceil$ [arXiv:2203.10064]. For simplicity, we use this formula for all single-qubit arbitrary angle rotations, and do not distinguish between best, worst, and average cases.

\n", + "
\n", + "
\n", + " \n", + " Logical qubit parameters\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
QEC schemesurface_code\n", + " Name of QEC scheme\n", + "
\n", + "

You can load pre-defined QEC schemes by using the name surface_code or floquet_code. The latter only works with Majorana qubits.

\n", + "
Code distance5\n", + " Required code distance for error correction\n", + "
\n", + "

The code distance is the smallest odd integer greater or equal to $\\dfrac{2\\log(0.03 / 0.0001666666666666667)}{\\log(0.01/0.001)} - 1$

\n", + "
Physical qubits50\n", + " Number of physical qubits per logical qubit\n", + "
\n", + "

The number of physical qubits per logical qubit are evaluated using the formula 2 * codeDistance * codeDistance that can be user-specified.

\n", + "
Logical cycle time2 microsecs\n", + " Duration of a logical cycle in nanoseconds\n", + "
\n", + "

The runtime of one logical cycle in nanoseconds is evaluated using the formula (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance that can be user-specified.

\n", + "
Logical qubit error rate3.00e-5\n", + " Logical qubit error rate\n", + "
\n", + "

The logical qubit error rate is computed as $0.03 \\cdot \\left(\\dfrac{0.001}{0.01}\\right)^\\frac{5 + 1}{2}$

\n", + "
Crossing prefactor0.03\n", + " Crossing prefactor used in QEC scheme\n", + "
\n", + "

The crossing prefactor is usually extracted numerically from simulations when fitting an exponential curve to model the relationship between logical and physical error rate.

\n", + "
Error correction threshold0.01\n", + " Error correction threshold used in QEC scheme\n", + "
\n", + "

The error correction threshold is the physical error rate below which the error rate of the logical qubit is less than the error rate of the physical qubit that constitute it. This value is usually extracted numerically from simulations of the logical error rate.

\n", + "
Logical cycle time formula(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance\n", + " QEC scheme formula used to compute logical cycle time\n", + "
\n", + "

This is the formula that is used to compute the logical cycle time 2,000 ns.

\n", + "
Physical qubits formula2 * codeDistance * codeDistance\n", + " QEC scheme formula used to compute number of physical qubits per logical qubit\n", + "
\n", + "

This is the formula that is used to compute the number of physical qubits per logical qubits 50.

\n", + "
\n", + "
\n", + " \n", + " Pre-layout logical resources\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Logical qubits (pre-layout)10\n", + " Number of logical qubits in the input quantum program\n", + "
\n", + "

We determine 30 algorithmic logical qubits from this number by assuming to align them in a 2D grid. Auxiliary qubits are added to allow for sufficient space to execute multi-qubit Pauli measurements on all or a subset of the logical qubits.

\n", + "
T gates0\n", + " Number of T gates in the input quantum program\n", + "
\n", + "

This includes all T gates and adjoint T gates, but not T gates used to implement rotation gates with arbitrary angle, CCZ gates, or CCiX gates.

\n", + "
Rotation gates0\n", + " Number of rotation gates in the input quantum program\n", + "
\n", + "

This is the number of all rotation gates. If an angle corresponds to a Pauli, Clifford, or T gate, it is not accounted for in this number.

\n", + "
Rotation depth0\n", + " Depth of rotation gates in the input quantum program\n", + "
\n", + "

This is the number of all non-Clifford layers that include at least one single-qubit rotation gate with an arbitrary angle.

\n", + "
CCZ gates0\n", + " Number of CCZ-gates in the input quantum program\n", + "
\n", + "

This is the number of CCZ gates.

\n", + "
CCiX gates0\n", + " Number of CCiX-gates in the input quantum program\n", + "
\n", + "

This is the number of CCiX gates, which applies $-iX$ controlled on two control qubits [1212.5069].

\n", + "
Measurement operations10\n", + " Number of single qubit measurements in the input quantum program\n", + "
\n", + "

This is the number of single qubit measurements in Pauli basis that are used in the input program. Note that all measurements are counted, however, the measurement result is is determined randomly (with a fixed seed) to be 0 or 1 with a probability of 50%.

\n", + "
\n", + "
\n", + " \n", + " Assumed error budget\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Total error budget5.00e-2\n", + " Total error budget for the algorithm\n", + "
\n", + "

The total error budget sets the overall allowed error for the algorithm, i.e., the number of times it is allowed to fail. Its value must be between 0 and 1 and the default value is 0.001, which corresponds to 0.1%, and means that the algorithm is allowed to fail once in 1000 executions. This parameter is highly application specific. For example, if one is running Shor's algorithm for factoring integers, a large value for the error budget may be tolerated as one can check that the output are indeed the prime factors of the input. On the other hand, a much smaller error budget may be needed for an algorithm solving a problem with a solution which cannot be efficiently verified. This budget $\\epsilon = \\epsilon_{\\log} + \\epsilon_{\\rm dis} + \\epsilon_{\\rm syn}$ is uniformly distributed and applies to errors $\\epsilon_{\\log}$ to implement logical qubits, an error budget $\\epsilon_{\\rm dis}$ to produce T states through distillation, and an error budget $\\epsilon_{\\rm syn}$ to synthesize rotation gates with arbitrary angles. Note that for distillation and rotation synthesis, the respective error budgets $\\epsilon_{\\rm dis}$ and $\\epsilon_{\\rm syn}$ are uniformly distributed among all T states and all rotation gates, respectively. If there are no rotation gates in the input algorithm, the error budget is uniformly distributed to logical errors and T state errors.

\n", + "
Logical error probability5.00e-2\n", + " Probability of at least one logical error\n", + "
\n", + "

This is one third of the total error budget 5.00e-2 if the input algorithm contains rotation with gates with arbitrary angles, or one half of it, otherwise.

\n", + "
T distillation error probability0.00e0\n", + " Probability of at least one faulty T distillation\n", + "
\n", + "

This is one third of the total error budget 5.00e-2 if the input algorithm contains rotation with gates with arbitrary angles, or one half of it, otherwise.

\n", + "
Rotation synthesis error probability0.00e0\n", + " Probability of at least one failed rotation synthesis\n", + "
\n", + "

This is one third of the total error budget 5.00e-2.

\n", + "
\n", + "
\n", + " \n", + " Physical qubit parameters\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Qubit namequbit_gate_ns_e3\n", + " Some descriptive name for the qubit model\n", + "
\n", + "

You can load pre-defined qubit parameters by using the names qubit_gate_ns_e3, qubit_gate_ns_e4, qubit_gate_us_e3, qubit_gate_us_e4, qubit_maj_ns_e4, or qubit_maj_ns_e6. The names of these pre-defined qubit parameters indicate the instruction set (gate-based or Majorana), the operation speed (ns or µs regime), as well as the fidelity (e.g., e3 for $10^{-3}$ gate error rates).

\n", + "
Instruction setGateBased\n", + " Underlying qubit technology (gate-based or Majorana)\n", + "
\n", + "

When modeling the physical qubit abstractions, we distinguish between two different physical instruction sets that are used to operate the qubits. The physical instruction set can be either gate-based or Majorana. A gate-based instruction set provides single-qubit measurement, single-qubit gates (incl. T gates), and two-qubit gates. A Majorana instruction set provides a physical T gate, single-qubit measurement and two-qubit joint measurement operations.

\n", + "
Single-qubit measurement time100 ns\n", + " Operation time for single-qubit measurement (t_meas) in ns\n", + "
\n", + "

This is the operation time in nanoseconds to perform a single-qubit measurement in the Pauli basis.

\n", + "
Single-qubit gate time50 ns\n", + " Operation time for single-qubit gate (t_gate) in ns\n", + "
\n", + "

This is the operation time in nanoseconds to perform a single-qubit Clifford operation, e.g., Hadamard or Phase gates.

\n", + "
Two-qubit gate time50 ns\n", + " Operation time for two-qubit gate in ns\n", + "
\n", + "

This is the operation time in nanoseconds to perform a two-qubit Clifford operation, e.g., a CNOT or CZ gate.

\n", + "
T gate time50 ns\n", + " Operation time for a T gate\n", + "
\n", + "

This is the operation time in nanoseconds to execute a T gate.

\n", + "
Single-qubit measurement error rate0.001\n", + " Error rate for single-qubit measurement\n", + "
\n", + "

This is the probability in which a single-qubit measurement in the Pauli basis may fail.

\n", + "
Single-qubit error rate0.001\n", + " Error rate for single-qubit Clifford gate (p)\n", + "
\n", + "

This is the probability in which a single-qubit Clifford operation, e.g., Hadamard or Phase gates, may fail.

\n", + "
Two-qubit error rate0.001\n", + " Error rate for two-qubit Clifford gate\n", + "
\n", + "

This is the probability in which a two-qubit Clifford operation, e.g., CNOT or CZ gates, may fail.

\n", + "
T gate error rate0.001\n", + " Error rate to prepare single-qubit T state or apply a T gate (p_T)\n", + "
\n", + "

This is the probability in which executing a single T gate may fail.

\n", + "
\n", + "
\n", + " \n", + " Constraints\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Logical depth factorconstraint not set\n", + " Factor, the initial number of logical cycles is multiplied by\n", + "
\n", + "

This is the factor takes into account a potential overhead to the initial number of logical cycles.

\n", + "
Maximum number of T factoriesconstraint not set\n", + " The maximum number of T factories can be utilized during the algorithm's runtime\n", + "
\n", + "

This is the maximum number of T factories used for producing the demanded T states, which can be created and executed by the algorithm in parallel.

\n", + "
Maximum runtime durationconstraint not set\n", + " The maximum runtime duration allowed for the algorithm runtime\n", + "
\n", + "

This is the maximum time allowed to the algorithm. If specified, the estimator targets to minimize the number of physical qubits consumed by the algorithm for runtimes under the maximum allowed.

\n", + "
Maximum number of physical qubitsconstraint not set\n", + " The maximum number of physical qubits allowed for utilization to the algorith\n", + "
\n", + "

This is the maximum number of physical qubits available to the algorithm. If specified, the estimator targets to minimize the runtime of the algorithm with number of physical qubits consumed not exceeding this maximum.

\n", + "
Assumptions
  • More details on the following lists of assumptions can be found in the paper Accessing requirements for scaling quantum computers and their applications.

  • Uniform independent physical noise. We assume that the noise on physical qubits and physical qubit operations is the standard circuit noise model. In particular we assume error events at different space-time locations are independent and that error rates are uniform across the system in time and space.

  • Efficient classical computation. We assume that classical overhead (compilation, control, feedback, readout, decoding, etc.) does not dominate the overall cost of implementing the full quantum algorithm.

  • Extraction circuits for planar quantum ISA. We assume that stabilizer extraction circuits with similar depth and error correction performance to those for standard surface and Hastings-Haah code patches can be constructed to implement all operations of the planar quantum ISA (instruction set architecture).

  • Uniform independent logical noise. We assume that the error rate of a logical operation is approximately equal to its space-time volume (the number of tiles multiplied by the number of logical time steps) multiplied by the error rate of a logical qubit in a standard one-tile patch in one logical time step.

  • Negligible Clifford costs for synthesis. We assume that the space overhead for synthesis and space and time overhead for transport of magic states within magic state factories and to synthesis qubits are all negligible.

  • Smooth magic state consumption rate. We assume that the rate of T state consumption throughout the compiled algorithm is almost constant, or can be made almost constant without significantly increasing the number of logical time steps for the algorithm.

" + ], + "text/plain": [ + "{'status': 'success',\n", + " 'jobParams': {'qecScheme': {'name': 'surface_code',\n", + " 'errorCorrectionThreshold': 0.01,\n", + " 'crossingPrefactor': 0.03,\n", + " 'logicalCycleTime': '(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance',\n", + " 'physicalQubitsPerLogicalQubit': '2 * codeDistance * codeDistance',\n", + " 'maxCodeDistance': 50},\n", + " 'errorBudget': 0.05,\n", + " 'qubitParams': {'instructionSet': 'GateBased',\n", + " 'name': 'qubit_gate_ns_e3',\n", + " 'oneQubitMeasurementTime': '100 ns',\n", + " 'oneQubitGateTime': '50 ns',\n", + " 'twoQubitGateTime': '50 ns',\n", + " 'tGateTime': '50 ns',\n", + " 'oneQubitMeasurementErrorRate': 0.001,\n", + " 'oneQubitGateErrorRate': 0.001,\n", + " 'twoQubitGateErrorRate': 0.001,\n", + " 'tGateErrorRate': 0.001,\n", + " 'idleErrorRate': 0.001}},\n", + " 'physicalCounts': {'physicalQubits': 1500,\n", + " 'runtime': 20000,\n", + " 'rqops': 15000000,\n", + " 'breakdown': {'algorithmicLogicalQubits': 30,\n", + " 'algorithmicLogicalDepth': 10,\n", + " 'logicalDepth': 10,\n", + " 'numTstates': 0,\n", + " 'clockFrequency': 500000.0,\n", + " 'numTfactories': 0,\n", + " 'numTfactoryRuns': 0,\n", + " 'physicalQubitsForTfactories': 0,\n", + " 'physicalQubitsForAlgorithm': 1500,\n", + " 'requiredLogicalQubitErrorRate': 0.0001666666666666667,\n", + " 'requiredLogicalTstateErrorRate': None,\n", + " 'numTsPerRotation': None,\n", + " 'cliffordErrorRate': 0.001}},\n", + " 'physicalCountsFormatted': {'runtime': '20 microsecs',\n", + " 'rqops': '15.00M',\n", + " 'physicalQubits': '1.50k',\n", + " 'algorithmicLogicalQubits': '30',\n", + " 'algorithmicLogicalDepth': '10',\n", + " 'logicalDepth': '10',\n", + " 'numTstates': '0',\n", + " 'numTfactories': '0',\n", + " 'numTfactoryRuns': '0',\n", + " 'physicalQubitsForAlgorithm': '1.50k',\n", + " 'physicalQubitsForTfactories': '0',\n", + " 'physicalQubitsForTfactoriesPercentage': '0.00 %',\n", + " 'requiredLogicalQubitErrorRate': '1.67e-4',\n", + " 'requiredLogicalTstateErrorRate': 'No T states in algorithm',\n", + " 'physicalQubitsPerLogicalQubit': '50',\n", + " 'logicalCycleTime': '2 microsecs',\n", + " 'clockFrequency': '500.00k',\n", + " 'logicalErrorRate': '3.00e-5',\n", + " 'tfactoryPhysicalQubits': 'No T states in algorithm',\n", + " 'tfactoryRuntime': 'No T states in algorithm',\n", + " 'numInputTstates': 'No T states in algorithm',\n", + " 'numUnitsPerRound': 'No T states in algorithm',\n", + " 'unitNamePerRound': 'No T states in algorithm',\n", + " 'codeDistancePerRound': 'No T states in algorithm',\n", + " 'physicalQubitsPerRound': 'No T states in algorithm',\n", + " 'tfactoryRuntimePerRound': 'No T states in algorithm',\n", + " 'tstateLogicalErrorRate': 'No T states in algorithm',\n", + " 'logicalCountsNumQubits': '10',\n", + " 'logicalCountsTCount': '0',\n", + " 'logicalCountsRotationCount': '0',\n", + " 'logicalCountsRotationDepth': '0',\n", + " 'logicalCountsCczCount': '0',\n", + " 'logicalCountsCcixCount': '0',\n", + " 'logicalCountsMeasurementCount': '10',\n", + " 'errorBudget': '5.00e-2',\n", + " 'errorBudgetLogical': '5.00e-2',\n", + " 'errorBudgetTstates': '0.00e0',\n", + " 'errorBudgetRotations': '0.00e0',\n", + " 'numTsPerRotation': 'No rotations in algorithm',\n", + " 'logicalDepthFactor': 'constraint not set',\n", + " 'maxTFactories': 'constraint not set',\n", + " 'maxDuration': 'constraint not set',\n", + " 'maxPhysicalQubits': 'constraint not set'},\n", + " 'logicalQubit': {'codeDistance': 5,\n", + " 'physicalQubits': 50,\n", + " 'logicalCycleTime': 2000,\n", + " 'logicalErrorRate': 3.0000000000000008e-05},\n", + " 'tfactory': None,\n", + " 'errorBudget': {'logical': 0.05, 'tstates': 0.0, 'rotations': 0.0},\n", + " 'logicalCounts': {'numQubits': 10,\n", + " 'tCount': 0,\n", + " 'rotationCount': 0,\n", + " 'rotationDepth': 0,\n", + " 'cczCount': 0,\n", + " 'ccixCount': 0,\n", + " 'measurementCount': 10},\n", + " 'reportData': {'groups': [{'title': 'Physical resource estimates',\n", + " 'alwaysVisible': True,\n", + " 'entries': [{'path': 'physicalCountsFormatted/runtime',\n", + " 'label': 'Runtime',\n", + " 'description': 'Total runtime',\n", + " 'explanation': 'This is a runtime estimate for the execution time of the algorithm. In general, the execution time corresponds to the duration of one logical cycle (2,000 nanosecs) multiplied by the 10 logical cycles to run the algorithm. If however the duration of a single T factory (here: 0 nanosecs) is larger than the algorithm runtime, we extend the number of logical cycles artificially in order to exceed the runtime of a single T factory.'},\n", + " {'path': 'physicalCountsFormatted/rqops',\n", + " 'label': 'rQOPS',\n", + " 'description': 'Reliable quantum operations per second',\n", + " 'explanation': 'The value is computed as the number of logical qubits after layout (30) (with a logical error rate of 1.67e-4) multiplied by the clock frequency (500,000.00), which is the number of logical cycles per second.'},\n", + " {'path': 'physicalCountsFormatted/physicalQubits',\n", + " 'label': 'Physical qubits',\n", + " 'description': 'Number of physical qubits',\n", + " 'explanation': 'This value represents the total number of physical qubits, which is the sum of 1,500 physical qubits to implement the algorithm logic, and 0 physical qubits to execute the T factories that are responsible to produce the T states that are consumed by the algorithm.'}]},\n", + " {'title': 'Resource estimates breakdown',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'physicalCountsFormatted/algorithmicLogicalQubits',\n", + " 'label': 'Logical algorithmic qubits',\n", + " 'description': 'Number of logical qubits for the algorithm after layout',\n", + " 'explanation': 'Laying out the logical qubits in the presence of nearest-neighbor constraints requires additional logical qubits. In particular, to layout the $Q_{\\\\rm alg} = 10$ logical qubits in the input algorithm, we require in total $2 \\\\cdot Q_{\\\\rm alg} + \\\\lceil \\\\sqrt{8 \\\\cdot Q_{\\\\rm alg}}\\\\rceil + 1 = 30$ logical qubits.'},\n", + " {'path': 'physicalCountsFormatted/algorithmicLogicalDepth',\n", + " 'label': 'Algorithmic depth',\n", + " 'description': 'Number of logical cycles for the algorithm',\n", + " 'explanation': 'To execute the algorithm using _Parallel Synthesis Sequential Pauli Computation_ (PSSPC), operations are scheduled in terms of multi-qubit Pauli measurements, for which assume an execution time of one logical cycle. Based on the input algorithm, we require one multi-qubit measurement for the 10 single-qubit measurements, the 0 arbitrary single-qubit rotations, and the 0 T gates, three multi-qubit measurements for each of the 0 CCZ and 0 CCiX gates in the input program, as well as No rotations in algorithm multi-qubit measurements for each of the 0 non-Clifford layers in which there is at least one single-qubit rotation with an arbitrary angle rotation.'},\n", + " {'path': 'physicalCountsFormatted/logicalDepth',\n", + " 'label': 'Logical depth',\n", + " 'description': 'Number of logical cycles performed',\n", + " 'explanation': \"This number is usually equal to the logical depth of the algorithm, which is 10. However, in the case in which a single T factory is slower than the execution time of the algorithm, we adjust the logical cycle depth to exceed the T factory's execution time.\"},\n", + " {'path': 'physicalCountsFormatted/clockFrequency',\n", + " 'label': 'Clock frequency',\n", + " 'description': 'Number of logical cycles per second',\n", + " 'explanation': 'This is the number of logical cycles that can be performed within one second. The logical cycle time is 2 microsecs.'},\n", + " {'path': 'physicalCountsFormatted/numTstates',\n", + " 'label': 'Number of T states',\n", + " 'description': 'Number of T states consumed by the algorithm',\n", + " 'explanation': 'To execute the algorithm, we require one T state for each of the 0 T gates, four T states for each of the 0 CCZ and 0 CCiX gates, as well as No rotations in algorithm for each of the 0 single-qubit rotation gates with arbitrary angle rotation.'},\n", + " {'path': 'physicalCountsFormatted/numTfactories',\n", + " 'label': 'Number of T factories',\n", + " 'description': \"Number of T factories capable of producing the demanded 0 T states during the algorithm's runtime\",\n", + " 'explanation': 'The total number of T factories 0 that are executed in parallel is computed as $\\\\left\\\\lceil\\\\dfrac{\\\\text{T states}\\\\cdot\\\\text{T factory duration}}{\\\\text{T states per T factory}\\\\cdot\\\\text{algorithm runtime}}\\\\right\\\\rceil = \\\\left\\\\lceil\\\\dfrac{0 \\\\cdot 0\\\\;\\\\text{ns}}{0 \\\\cdot 20,000\\\\;\\\\text{ns}}\\\\right\\\\rceil$'},\n", + " {'path': 'physicalCountsFormatted/numTfactoryRuns',\n", + " 'label': 'Number of T factory invocations',\n", + " 'description': 'Number of times all T factories are invoked',\n", + " 'explanation': 'In order to prepare the 0 T states, the 0 copies of the T factory are repeatedly invoked 0 times.'},\n", + " {'path': 'physicalCountsFormatted/physicalQubitsForAlgorithm',\n", + " 'label': 'Physical algorithmic qubits',\n", + " 'description': 'Number of physical qubits for the algorithm after layout',\n", + " 'explanation': 'The 1,500 are the product of the 30 logical qubits after layout and the 50 physical qubits that encode a single logical qubit.'},\n", + " {'path': 'physicalCountsFormatted/physicalQubitsForTfactories',\n", + " 'label': 'Physical T factory qubits',\n", + " 'description': 'Number of physical qubits for the T factories',\n", + " 'explanation': 'Each T factory requires 0 physical qubits and we run 0 in parallel, therefore we need $0 = 0 \\\\cdot 0$ qubits.'},\n", + " {'path': 'physicalCountsFormatted/requiredLogicalQubitErrorRate',\n", + " 'label': 'Required logical qubit error rate',\n", + " 'description': 'The minimum logical qubit error rate required to run the algorithm within the error budget',\n", + " 'explanation': 'The minimum logical qubit error rate is obtained by dividing the logical error probability 5.00e-2 by the product of 30 logical qubits and the total cycle count 10.'},\n", + " {'path': 'physicalCountsFormatted/requiredLogicalTstateErrorRate',\n", + " 'label': 'Required logical T state error rate',\n", + " 'description': 'The minimum T state error rate required for distilled T states',\n", + " 'explanation': 'The minimum T state error rate is obtained by dividing the T distillation error probability 0.00e0 by the total number of T states 0.'},\n", + " {'path': 'physicalCountsFormatted/numTsPerRotation',\n", + " 'label': 'Number of T states per rotation',\n", + " 'description': 'Number of T states to implement a rotation with an arbitrary angle',\n", + " 'explanation': 'The number of T states to implement a rotation with an arbitrary angle is $\\\\lceil 0.53 \\\\log_2(0 / 0) + 5.3\\\\rceil$ [[arXiv:2203.10064](https://arxiv.org/abs/2203.10064)]. For simplicity, we use this formula for all single-qubit arbitrary angle rotations, and do not distinguish between best, worst, and average cases.'}]},\n", + " {'title': 'Logical qubit parameters',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'jobParams/qecScheme/name',\n", + " 'label': 'QEC scheme',\n", + " 'description': 'Name of QEC scheme',\n", + " 'explanation': 'You can load pre-defined QEC schemes by using the name `surface_code` or `floquet_code`. The latter only works with Majorana qubits.'},\n", + " {'path': 'logicalQubit/codeDistance',\n", + " 'label': 'Code distance',\n", + " 'description': 'Required code distance for error correction',\n", + " 'explanation': 'The code distance is the smallest odd integer greater or equal to $\\\\dfrac{2\\\\log(0.03 / 0.0001666666666666667)}{\\\\log(0.01/0.001)} - 1$'},\n", + " {'path': 'physicalCountsFormatted/physicalQubitsPerLogicalQubit',\n", + " 'label': 'Physical qubits',\n", + " 'description': 'Number of physical qubits per logical qubit',\n", + " 'explanation': 'The number of physical qubits per logical qubit are evaluated using the formula 2 * codeDistance * codeDistance that can be user-specified.'},\n", + " {'path': 'physicalCountsFormatted/logicalCycleTime',\n", + " 'label': 'Logical cycle time',\n", + " 'description': 'Duration of a logical cycle in nanoseconds',\n", + " 'explanation': 'The runtime of one logical cycle in nanoseconds is evaluated using the formula (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance that can be user-specified.'},\n", + " {'path': 'physicalCountsFormatted/logicalErrorRate',\n", + " 'label': 'Logical qubit error rate',\n", + " 'description': 'Logical qubit error rate',\n", + " 'explanation': 'The logical qubit error rate is computed as $0.03 \\\\cdot \\\\left(\\\\dfrac{0.001}{0.01}\\\\right)^\\\\frac{5 + 1}{2}$'},\n", + " {'path': 'jobParams/qecScheme/crossingPrefactor',\n", + " 'label': 'Crossing prefactor',\n", + " 'description': 'Crossing prefactor used in QEC scheme',\n", + " 'explanation': 'The crossing prefactor is usually extracted numerically from simulations when fitting an exponential curve to model the relationship between logical and physical error rate.'},\n", + " {'path': 'jobParams/qecScheme/errorCorrectionThreshold',\n", + " 'label': 'Error correction threshold',\n", + " 'description': 'Error correction threshold used in QEC scheme',\n", + " 'explanation': 'The error correction threshold is the physical error rate below which the error rate of the logical qubit is less than the error rate of the physical qubit that constitute it. This value is usually extracted numerically from simulations of the logical error rate.'},\n", + " {'path': 'jobParams/qecScheme/logicalCycleTime',\n", + " 'label': 'Logical cycle time formula',\n", + " 'description': 'QEC scheme formula used to compute logical cycle time',\n", + " 'explanation': 'This is the formula that is used to compute the logical cycle time 2,000 ns.'},\n", + " {'path': 'jobParams/qecScheme/physicalQubitsPerLogicalQubit',\n", + " 'label': 'Physical qubits formula',\n", + " 'description': 'QEC scheme formula used to compute number of physical qubits per logical qubit',\n", + " 'explanation': 'This is the formula that is used to compute the number of physical qubits per logical qubits 50.'}]},\n", + " {'title': 'Pre-layout logical resources',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'physicalCountsFormatted/logicalCountsNumQubits',\n", + " 'label': 'Logical qubits (pre-layout)',\n", + " 'description': 'Number of logical qubits in the input quantum program',\n", + " 'explanation': 'We determine 30 algorithmic logical qubits from this number by assuming to align them in a 2D grid. Auxiliary qubits are added to allow for sufficient space to execute multi-qubit Pauli measurements on all or a subset of the logical qubits.'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsTCount',\n", + " 'label': 'T gates',\n", + " 'description': 'Number of T gates in the input quantum program',\n", + " 'explanation': 'This includes all T gates and adjoint T gates, but not T gates used to implement rotation gates with arbitrary angle, CCZ gates, or CCiX gates.'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsRotationCount',\n", + " 'label': 'Rotation gates',\n", + " 'description': 'Number of rotation gates in the input quantum program',\n", + " 'explanation': 'This is the number of all rotation gates. If an angle corresponds to a Pauli, Clifford, or T gate, it is not accounted for in this number.'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsRotationDepth',\n", + " 'label': 'Rotation depth',\n", + " 'description': 'Depth of rotation gates in the input quantum program',\n", + " 'explanation': 'This is the number of all non-Clifford layers that include at least one single-qubit rotation gate with an arbitrary angle.'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsCczCount',\n", + " 'label': 'CCZ gates',\n", + " 'description': 'Number of CCZ-gates in the input quantum program',\n", + " 'explanation': 'This is the number of CCZ gates.'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsCcixCount',\n", + " 'label': 'CCiX gates',\n", + " 'description': 'Number of CCiX-gates in the input quantum program',\n", + " 'explanation': 'This is the number of CCiX gates, which applies $-iX$ controlled on two control qubits [[1212.5069](https://arxiv.org/abs/1212.5069)].'},\n", + " {'path': 'physicalCountsFormatted/logicalCountsMeasurementCount',\n", + " 'label': 'Measurement operations',\n", + " 'description': 'Number of single qubit measurements in the input quantum program',\n", + " 'explanation': 'This is the number of single qubit measurements in Pauli basis that are used in the input program. Note that all measurements are counted, however, the measurement result is is determined randomly (with a fixed seed) to be 0 or 1 with a probability of 50%.'}]},\n", + " {'title': 'Assumed error budget',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'physicalCountsFormatted/errorBudget',\n", + " 'label': 'Total error budget',\n", + " 'description': 'Total error budget for the algorithm',\n", + " 'explanation': \"The total error budget sets the overall allowed error for the algorithm, i.e., the number of times it is allowed to fail. Its value must be between 0 and 1 and the default value is 0.001, which corresponds to 0.1%, and means that the algorithm is allowed to fail once in 1000 executions. This parameter is highly application specific. For example, if one is running Shor's algorithm for factoring integers, a large value for the error budget may be tolerated as one can check that the output are indeed the prime factors of the input. On the other hand, a much smaller error budget may be needed for an algorithm solving a problem with a solution which cannot be efficiently verified. This budget $\\\\epsilon = \\\\epsilon_{\\\\log} + \\\\epsilon_{\\\\rm dis} + \\\\epsilon_{\\\\rm syn}$ is uniformly distributed and applies to errors $\\\\epsilon_{\\\\log}$ to implement logical qubits, an error budget $\\\\epsilon_{\\\\rm dis}$ to produce T states through distillation, and an error budget $\\\\epsilon_{\\\\rm syn}$ to synthesize rotation gates with arbitrary angles. Note that for distillation and rotation synthesis, the respective error budgets $\\\\epsilon_{\\\\rm dis}$ and $\\\\epsilon_{\\\\rm syn}$ are uniformly distributed among all T states and all rotation gates, respectively. If there are no rotation gates in the input algorithm, the error budget is uniformly distributed to logical errors and T state errors.\"},\n", + " {'path': 'physicalCountsFormatted/errorBudgetLogical',\n", + " 'label': 'Logical error probability',\n", + " 'description': 'Probability of at least one logical error',\n", + " 'explanation': 'This is one third of the total error budget 5.00e-2 if the input algorithm contains rotation with gates with arbitrary angles, or one half of it, otherwise.'},\n", + " {'path': 'physicalCountsFormatted/errorBudgetTstates',\n", + " 'label': 'T distillation error probability',\n", + " 'description': 'Probability of at least one faulty T distillation',\n", + " 'explanation': 'This is one third of the total error budget 5.00e-2 if the input algorithm contains rotation with gates with arbitrary angles, or one half of it, otherwise.'},\n", + " {'path': 'physicalCountsFormatted/errorBudgetRotations',\n", + " 'label': 'Rotation synthesis error probability',\n", + " 'description': 'Probability of at least one failed rotation synthesis',\n", + " 'explanation': 'This is one third of the total error budget 5.00e-2.'}]},\n", + " {'title': 'Physical qubit parameters',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'jobParams/qubitParams/name',\n", + " 'label': 'Qubit name',\n", + " 'description': 'Some descriptive name for the qubit model',\n", + " 'explanation': 'You can load pre-defined qubit parameters by using the names `qubit_gate_ns_e3`, `qubit_gate_ns_e4`, `qubit_gate_us_e3`, `qubit_gate_us_e4`, `qubit_maj_ns_e4`, or `qubit_maj_ns_e6`. The names of these pre-defined qubit parameters indicate the instruction set (gate-based or Majorana), the operation speed (ns or µs regime), as well as the fidelity (e.g., e3 for $10^{-3}$ gate error rates).'},\n", + " {'path': 'jobParams/qubitParams/instructionSet',\n", + " 'label': 'Instruction set',\n", + " 'description': 'Underlying qubit technology (gate-based or Majorana)',\n", + " 'explanation': 'When modeling the physical qubit abstractions, we distinguish between two different physical instruction sets that are used to operate the qubits. The physical instruction set can be either *gate-based* or *Majorana*. A gate-based instruction set provides single-qubit measurement, single-qubit gates (incl. T gates), and two-qubit gates. A Majorana instruction set provides a physical T gate, single-qubit measurement and two-qubit joint measurement operations.'},\n", + " {'path': 'jobParams/qubitParams/oneQubitMeasurementTime',\n", + " 'label': 'Single-qubit measurement time',\n", + " 'description': 'Operation time for single-qubit measurement (t_meas) in ns',\n", + " 'explanation': 'This is the operation time in nanoseconds to perform a single-qubit measurement in the Pauli basis.'},\n", + " {'path': 'jobParams/qubitParams/oneQubitGateTime',\n", + " 'label': 'Single-qubit gate time',\n", + " 'description': 'Operation time for single-qubit gate (t_gate) in ns',\n", + " 'explanation': 'This is the operation time in nanoseconds to perform a single-qubit Clifford operation, e.g., Hadamard or Phase gates.'},\n", + " {'path': 'jobParams/qubitParams/twoQubitGateTime',\n", + " 'label': 'Two-qubit gate time',\n", + " 'description': 'Operation time for two-qubit gate in ns',\n", + " 'explanation': 'This is the operation time in nanoseconds to perform a two-qubit Clifford operation, e.g., a CNOT or CZ gate.'},\n", + " {'path': 'jobParams/qubitParams/tGateTime',\n", + " 'label': 'T gate time',\n", + " 'description': 'Operation time for a T gate',\n", + " 'explanation': 'This is the operation time in nanoseconds to execute a T gate.'},\n", + " {'path': 'jobParams/qubitParams/oneQubitMeasurementErrorRate',\n", + " 'label': 'Single-qubit measurement error rate',\n", + " 'description': 'Error rate for single-qubit measurement',\n", + " 'explanation': 'This is the probability in which a single-qubit measurement in the Pauli basis may fail.'},\n", + " {'path': 'jobParams/qubitParams/oneQubitGateErrorRate',\n", + " 'label': 'Single-qubit error rate',\n", + " 'description': 'Error rate for single-qubit Clifford gate (p)',\n", + " 'explanation': 'This is the probability in which a single-qubit Clifford operation, e.g., Hadamard or Phase gates, may fail.'},\n", + " {'path': 'jobParams/qubitParams/twoQubitGateErrorRate',\n", + " 'label': 'Two-qubit error rate',\n", + " 'description': 'Error rate for two-qubit Clifford gate',\n", + " 'explanation': 'This is the probability in which a two-qubit Clifford operation, e.g., CNOT or CZ gates, may fail.'},\n", + " {'path': 'jobParams/qubitParams/tGateErrorRate',\n", + " 'label': 'T gate error rate',\n", + " 'description': 'Error rate to prepare single-qubit T state or apply a T gate (p_T)',\n", + " 'explanation': 'This is the probability in which executing a single T gate may fail.'}]},\n", + " {'title': 'Constraints',\n", + " 'alwaysVisible': False,\n", + " 'entries': [{'path': 'physicalCountsFormatted/logicalDepthFactor',\n", + " 'label': 'Logical depth factor',\n", + " 'description': 'Factor, the initial number of logical cycles is multiplied by',\n", + " 'explanation': 'This is the factor takes into account a potential overhead to the initial number of logical cycles.'},\n", + " {'path': 'physicalCountsFormatted/maxTFactories',\n", + " 'label': 'Maximum number of T factories',\n", + " 'description': \"The maximum number of T factories can be utilized during the algorithm's runtime\",\n", + " 'explanation': 'This is the maximum number of T factories used for producing the demanded T states, which can be created and executed by the algorithm in parallel.'},\n", + " {'path': 'physicalCountsFormatted/maxDuration',\n", + " 'label': 'Maximum runtime duration',\n", + " 'description': 'The maximum runtime duration allowed for the algorithm runtime',\n", + " 'explanation': 'This is the maximum time allowed to the algorithm. If specified, the estimator targets to minimize the number of physical qubits consumed by the algorithm for runtimes under the maximum allowed.'},\n", + " {'path': 'physicalCountsFormatted/maxPhysicalQubits',\n", + " 'label': 'Maximum number of physical qubits',\n", + " 'description': 'The maximum number of physical qubits allowed for utilization to the algorith',\n", + " 'explanation': 'This is the maximum number of physical qubits available to the algorithm. If specified, the estimator targets to minimize the runtime of the algorithm with number of physical qubits consumed not exceeding this maximum.'}]}],\n", + " 'assumptions': ['_More details on the following lists of assumptions can be found in the paper [Accessing requirements for scaling quantum computers and their applications](https://aka.ms/AQ/RE/Paper)._',\n", + " '**Uniform independent physical noise.** We assume that the noise on physical qubits and physical qubit operations is the standard circuit noise model. In particular we assume error events at different space-time locations are independent and that error rates are uniform across the system in time and space.',\n", + " '**Efficient classical computation.** We assume that classical overhead (compilation, control, feedback, readout, decoding, etc.) does not dominate the overall cost of implementing the full quantum algorithm.',\n", + " '**Extraction circuits for planar quantum ISA.** We assume that stabilizer extraction circuits with similar depth and error correction performance to those for standard surface and Hastings-Haah code patches can be constructed to implement all operations of the planar quantum ISA (instruction set architecture).',\n", + " '**Uniform independent logical noise.** We assume that the error rate of a logical operation is approximately equal to its space-time volume (the number of tiles multiplied by the number of logical time steps) multiplied by the error rate of a logical qubit in a standard one-tile patch in one logical time step.',\n", + " '**Negligible Clifford costs for synthesis.** We assume that the space overhead for synthesis and space and time overhead for transport of magic states within magic state factories and to synthesis qubits are all negligible.',\n", + " '**Smooth magic state consumption rate.** We assume that the rate of T state consumption throughout the compiled algorithm is almost constant, or can be made almost constant without significantly increasing the number of logical time steps for the algorithm.']}}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "job.result()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/qbraid_qir/qbraid-autoqasm-poc.ipynb b/qbraid_qir/qbraid-autoqasm-poc.ipynb new file mode 100644 index 0000000..5e36bd3 --- /dev/null +++ b/qbraid_qir/qbraid-autoqasm-poc.ipynb @@ -0,0 +1,424 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2f3000f-4271-421a-8ed5-d0fbd7af8629", + "metadata": { + "tags": [] + }, + "source": [ + "# AutoQASM x qBraid-QIR integration POC\n", + "\n", + "\n", + "## Overview\n", + "\n", + "This proof of concept demonstrates one potential approach to the integration between the AutoQASM and qBraid open-source projects, aiming to facilitate seamless conversion from AutoQASM to Quantum Intermediate Representation (QIR). This integration would enhance the interoperability of all involved quantum software frameworks and enable submission of quantum jobs to QIR-compatible devices using AutoQASM.\n", + "\n", + "## Resources\n", + "\n", + "\n", + "[OpenQASM](https://openqasm.com/): Quantum assembly language that enables complex quantum programming by supporting classical logic, timing controls, and procedural programming within quantum circuits.\n", + "\n", + "[QIR](https://www.qir-alliance.org/): Quantum intermediate representation based on LLVM, designed to facilitate optimization and cross-platform compatibility between different quantum processors and development tools.\n", + "\n", + "[AutoQASM](https://github.com/amazon-braket/autoqasm): Experimental Python-embedded module designed to enable a Pythonic, imperative programming experience for constructing OpenQASM programs.\n", + "\n", + "[qBraid-SDK](https://github.com/qBraid/qBraid): Platform-agnostic quantum runtime framework designed to streamline the full lifecycle management of quantum jobs—from defining program specifications, to job submission, and through to processing of results.\n", + "\n", + "[qBraid-QIR](): qBraid-SDK extension providing support for QIR conversions, including OpenQASM 3 $\\rightarrow$ QIR. \n", + "\n", + "\n", + "## Goals\n", + "\n", + "**Enhance Interoperability**: Ensure that AutoQASM seamlessly interacts with other quantum computing platforms to broaden its application scope.\n", + "\n", + "**Submit Quantum Jobs**: Facilitate the submission of quantum jobs written in AutoQASM to the remote qBraid QIR simulator (June 2024), leveraging the strengths of both systems to provide a great end-user experience." + ] + }, + { + "cell_type": "markdown", + "id": "b99d4134-30ae-476b-b1c5-b2f8a1d5bdee", + "metadata": {}, + "source": [ + "Run this notebook on [lab.qbraid.com](https://lab.qbraid.com) with environment access code:`592ca9a2-0881-41c4-bbf1-4b27d604afb1`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6d5737d1-b6a7-47ec-bae0-c0499ccdbdf1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import warnings\n", + "\n", + "warnings.filterwarnings(\n", + " \"ignore\",\n", + " message=\"networkx backend defined more than once: nx-loopback\",\n", + " category=RuntimeWarning,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "bc44ec7c-3a25-4f0e-b7bd-2eb633743ed4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import re\n", + "\n", + "import autoqasm as aq\n", + "from autoqasm.instructions import cnot, h, measure\n", + "\n", + "import qbraid\n", + "from qbraid.passes.qasm3.compat import add_stdgates_include, insert_gate_def\n", + "from qbraid.programs import QPROGRAM_REGISTRY, register_program_type\n", + "from qbraid.runtime.native import QbraidProvider\n", + "from qbraid.transpiler import Conversion, ConversionGraph, transpile\n", + "from qbraid.visualization.plot_counts import plot_histogram" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9af4d088-bae1-41db-9cb6-1d26aa447eb6", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "qBraid-SDK: A platform-agnostic quantum runtime framework\n", + "======================================================================\n", + "(C) 2024 qBraid Development Team (https://github.com/qBraid/qBraid)\n", + "\n", + "qbraid:\t0.7.0.dev\n", + "\n", + "Core Dependencies\n", + "-----------------\n", + "networkx: 3.2.1\n", + "openqasm3: 0.5.0\n", + "numpy: 1.26.4\n", + "ply: 3.11\n", + "\n", + "Optional Dependencies\n", + "---------------------\n", + "qbraid_core: 0.1.6\n", + "qbraid_qir: 0.2.0\n", + "braket: 1.79.1.dev0\n", + "\n", + "Python: 3.9.18\n", + "Platform: Linux (x86_64)\n" + ] + } + ], + "source": [ + "qbraid.about()" + ] + }, + { + "cell_type": "markdown", + "id": "e86eec25-d4f2-415e-a6b3-39285acff1bb", + "metadata": {}, + "source": [ + "### OpenQASM 3 IR compatibility\n", + "\n", + "The following function is where most of the collaboration will need to take place. In this function, we need to convert the OpenQASM 3 programs generated from AutoQASM into a format compatible with the qBraid-QIR qasm3 converter.\n", + "\n", + "\n", + "There are some OpenQASM 3 operations, such as pulse-level operations, that are not supported by QIR which we can omit for the time being. A good first step would be to ensure coverage for the entire OpenQASM 3 standard gate set. Within this gate set, there are a number of discrepancies between the AutoQASM output IR format and the supported qBraid-QIR OpenQASM 3 program input for gates like the S, T, square root of X, and phase gates, as well as in the ways measurement and qubit state initialization are handled.\n", + "\n", + "\n", + "Below is a basic, proof-of-concept implementation that shows what this type of bridge might look like, designed solely for internal demonstration purposes. Again, this cross-compatibility function will be central to the success of the integration." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3e8e6da9-6128-4195-9ef5-2d8247d3b5c9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def _process_qasm(qasm: str) -> str:\n", + " \"\"\"\n", + " Convert OpenQASM 3 string to a format that\n", + " will be accepted by the qbraid-qir converter.\n", + "\n", + " Args:\n", + " qasm (str): The input QASM string to process.\n", + "\n", + " Returns:\n", + " The processed QASM string.\n", + "\n", + " \"\"\"\n", + " # Regular expression to remove initialization to zeros\n", + " pattern = r'(bit\\[\\d+\\] +__bit_\\d+__)\\s+=\\s+\"[0]+\"(;)'\n", + "\n", + " # Transform each line, removing zero initializations\n", + " transformed_lines = [re.sub(pattern, r\"\\1\\2\", line) for line in qasm.split(\"\\n\")]\n", + "\n", + " # Rejoin the transformed lines back into a single string\n", + " qasm = \"\\n\".join(transformed_lines)\n", + "\n", + " # Replace specific keywords with comments in a single step to avoid multiple replacements\n", + " qasm = re.sub(r\"^(output|return_value =)\", r\"// \\1\", qasm, flags=re.MULTILINE)\n", + "\n", + " # Insert and replace various gate definitions for compatibility\n", + " qasm = add_stdgates_include(qasm)\n", + " qasm = insert_gate_def(qasm, \"iswap\")\n", + " qasm = insert_gate_def(qasm, \"sxdg\")\n", + "\n", + " return qasm\n", + "\n", + "\n", + "def autoqasm_to_qasm3(program: aq.program.MainProgram) -> str:\n", + " \"\"\"\n", + " Convert AutoQASM program to OpenQASM 3 string in a format that\n", + " will be accepted by the qbraid-qir converter.\n", + "\n", + " \"\"\"\n", + " qasm = program.build().to_ir()\n", + "\n", + " return _process_qasm(qasm)" + ] + }, + { + "cell_type": "markdown", + "id": "223e0b33-79c0-44be-8363-2ec08432a86d", + "metadata": {}, + "source": [ + "### Registering AutoQASM program type with qBraid conversion graph" + ] + }, + { + "cell_type": "markdown", + "id": "2bd65768-cb0f-492e-acfe-b1fbb378ae40", + "metadata": {}, + "source": [ + "The qBraid-SDK does not assume a fixed input or output/target software framework. Instead, it allows providers to dynamically register any desired run input program type as the target, depending on their specific needs." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "76fd47aa-bbb1-477c-8226-7915c222348c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "register_program_type(aq.program.MainProgram)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0bfecc00-c00d-406f-94e1-b77558e2772a", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'braket': braket.circuits.circuit.Circuit,\n", + " 'openqasm3': openqasm3.ast.Program,\n", + " 'pyqir': Module,\n", + " 'qasm2': str,\n", + " 'qasm3': str,\n", + " 'autoqasm': autoqasm.program.program.MainProgram}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "QPROGRAM_REGISTRY" + ] + }, + { + "cell_type": "markdown", + "id": "168396ea-fa61-48c7-8835-ebdd6ea70af7", + "metadata": {}, + "source": [ + "Registered program types are then interconnected via a graph-based transpiler, where each program type is represented as a node and supported conversions as edges. The breadth, depth, and connectivity can be customized by the provider." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "08eca693-942d-4c49-95a7-a940443a3710", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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s88+S+3atfn6669NZRo2bEhCQgLHjh0DICwsjE8++YTevXubynz66ads2LCB/fv359v1QAmZjlgIUbxcjU8uUokAGGsHrt1LpqqPC7aPM3lZZCTcuJHvceW35557LssdroeHh+n/tra2LF26lGrVqlG2bFm+/PLLXB+7du3aZj8nJCQwceJE1q9fT0REBBkZGSQnJ5tqBlq2bEnZsmUJCQmhTZs2tGnThi5duuDgkP1kUE5O/y07369fP2bPnp1jLF9++SUtWrQw2xYQEADA6dOn6dKli9lz9erVY9OmTaafz549yyuvvGJW5plnnmHHjh0AJCYmEh4eztChQxk+fLipTEZGBq6urjnGpSZJBoQQhepiEekr8CCDYkxkwtwd876zn1/+B1QA53V0dCQsLOyhZTLvaqOjo4mOjsbRMXevx4Plxo4dy9atW5k6dSphYWHY29vTrVs30tKMk085Oztz5MgRdu3axZYtW/jwww+ZOHEihw8fzrazX+YdOYCLi8tDY/Hz83vkdT6JhATjCJR58+ZRt25ds+cerJGwFJIMCCEKTWqGgXtpGWqHkSsGg4Fda37h4NYNXDp9koS4WAICyzKkf1/Gjh2bt+rYXFbVW7rw8HDeeOMN5s2bx/Llyxk4cCDbtm1DqzXWltja2qLX526lyX379jFo0CDTXXhCQgKXL182K2NtbU2LFi1o0aIFEyZMwM3NjR07dtC1a9csx8uvL/dKlSpx8OBBs20HDhww+7lChQocPnyYAQMGmLYdPnzY9H9fX18CAgK4ePEiffv2zZe4CpokA0KIQhObWnQ64aUmJ/PNe29QvnotWvUagKuHFxeO/82ECRPYvn07O3bsQKMpKt0gcyc1NZXIB/o2WFtb4+XlhV6vp1+/frRu3ZrBgwfTpk0bqlatyrRp03jrrbcACAoK4uDBg1y+fBknJyezJoYHlStXjtWrV9OhQwc0Gg3jx4/HYPhvqOnvv//OxYsXady4Me7u7mzYsAGDwUCFChWe+DpjY2OzXKezszOOjo689tprNGjQgKlTp9KpUyc2b95s1kQAMGrUKIYPH07t2rWpX78+y5cv559//iEkJMRU5qOPPuK1117D1dWVNm3akJqayl9//UVMTAxvvvnmE19DfpPRBEKIQhOTkl5kRhFY29gwadlapiz/jW4vv07LHn0ZMWk6748fz65d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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "graph = ConversionGraph()\n", + "\n", + "aq_conversion = Conversion(\"autoqasm\", \"qasm3\", autoqasm_to_qasm3)\n", + "\n", + "graph.add_conversion(aq_conversion)\n", + "\n", + "graph.plot(legend=True)" + ] + }, + { + "cell_type": "markdown", + "id": "1f74a345-d794-4f12-bc80-80b47f94d2d2", + "metadata": {}, + "source": [ + "### Submitting AutoQASM program to qBraid QIR simulator" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b1462227-284e-4ad2-818a-3e32c706b45d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "provider = QbraidProvider()\n", + "\n", + "device = provider.get_device(\"qbraid_qir_simulator\")\n", + "\n", + "device.update_scheme(conversion_graph=graph)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "10c9649e-a8d4-497c-a6e7-6a355a6e5b25", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "@aq.main\n", + "def bell_state():\n", + " h(0)\n", + " cnot(0, 1)\n", + " return measure([0, 1])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "62fa4dff-fc4f-4380-92a1-ba8f27dcc7f7", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "job = device.run(bell_state, shots=100)\n", + "\n", + "job.status()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0df2f88e-b4bf-4885-9538-ddf5e70cf808", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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q/sAAAA4Y9/oHpmCggL961//ktT6d5JGjRrVJU0BAACcjk4FmQMHDmjWrFlat26d76PRR44c0cSJE7Vy5Ur17du3K3sEAAA4oU59/Pree+9VfX29duzYoUOHDunQoUPavn27nE6nfvzjH3d1jwAAACfUqTMy7777rtauXashQ4b4akOHDtXixYvP6GZfAACAb6JTZ2Q8Ho+CgoKOqwcFBcnj8ZzgGQAAAF2vU0Fm0qRJ+slPfqLKykpfbf/+/Zo7d64uu+yyLmsOAADgVDoVZP7rv/5LTqdTycnJGjhwoAYOHKiUlBQ5nU796U9/6uoeAQAATqhT98gkJCRo8+bNWrt2rb744gtJ0pAhQzR58uQubQ4AAOBUzuiMzAcffKChQ4fK6XTKMAx95zvf0b333qt7771X2dnZGjZsmD766KOz1SsAAEAHZxRkFi1apDvvvFMRERHHLYuMjNSPfvQjPfHEE13WHAAAwKmcUZDZsmWLrrjiipMuv/zyy1VQUPCNmwIAADgdZxRkampqTvix62N69Oih2trab9wUAADA6TijINO/f39t3779pMu3bt2quLi4b9wUAADA6TijIHPVVVfpoYceUlNT03HLjh49qt/85je6+uqru6w5AACAUzmjj1//+te/1quvvqrBgwfrnnvuUXp6uiTpiy++0OLFi+V2u/WrX/3qrDQKAADwf51RkLHb7fr0009111136cEHH5TX65UkGYahKVOmaPHixbLb7WelUQAAgP/rjL8QLykpSW+//bYOHz6skpISeb1epaWlKSoq6mz0BwAAcFKd+mZfSYqKilJ2dnZX9gIAAHBGOvW3lgAAALoDggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALAsggwAALCsgAaZBQsWKDs7W7169VK/fv10/fXXq6ioqMM6TU1NuvvuuxUdHa3w8HBNnz5dNTU1AeoYAAB0JwENMnl5ebr77ru1YcMGvf/++2ppadHll1+uxsZG3zpz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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result = job.result()\n", + "\n", + "counts = result.measurement_counts()\n", + "\n", + "plot_histogram(counts)" + ] + }, + { + "cell_type": "markdown", + "id": "7edaff03-26c3-4370-9f91-8b028b625732", + "metadata": {}, + "source": [ + "
\n", + "Copyright Notice: \n", + " All rights reserved © [2024] qBraid. This notebook is part of the qBraid-SDK.\n", + "The qBraid-SDK is free software released under the GNU General Public License v3\n", + "or later. You can redistribute and/or modify it under the terms of the GPL v3.\n", + "See the LICENSE file in the project root or . THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a44c223-fef0-4f58-8451-cf075a154cd7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 [AutoQASM]", + "language": "python", + "name": "python3_autoqa_8a87m9" + }, + "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.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qbraid_qir/qbraid_transpiler_braket_to_qir.ipynb b/qbraid_qir/qbraid_transpiler_braket_to_qir.ipynb new file mode 100644 index 0000000..f86a6a6 --- /dev/null +++ b/qbraid_qir/qbraid_transpiler_braket_to_qir.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "a392d114", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install qbraid --quiet\n", + "%pip install qbraid-qir --quiet\n", + "%pip install cirq-core --quiet\n", + "%pip install amazon-braket-sdk --quiet\n", + "%pip install matplotlib --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b8c12461", + "metadata": {}, + "outputs": [], + "source": [ + "from braket.circuits import Circuit\n", + "from qbraid import SUPPORTED_QPROGRAMS\n", + "from qbraid.transpiler import Conversion, ConversionGraph, convert_to_package\n", + "\n", + "from qbraid_qir import dumps\n", + "from qbraid_qir.cirq import cirq_to_qir" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7a6b913a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'cirq': 'cirq.circuits.circuit.Circuit',\n", + " 'braket': 'braket.circuits.circuit.Circuit',\n", + " 'openqasm3': 'openqasm3.ast.Program',\n", + " 'qasm2': 'str',\n", + " 'qasm3': 'str'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "SUPPORTED_QPROGRAMS" + ] + }, + { + "cell_type": "markdown", + "id": "3a5939aa-ef56-428f-8fdd-2ed428f14ba3", + "metadata": {}, + "source": [ + "Default qBraid-SDK conversion graph with Amazon Braket and Cirq nodes" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "474e8d08", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Rp5++mmuXbvGu+++y5gxY+jTpw+bNm3ipZde4vTp08yaNYsXXniBb7755q7OU9i8GhwcbN2WmprKoEGDGDduHPfffz/h4eHk5eXRq1cvTp8+zVNPPUXdunWZP38+kyZNIj09nb/85S/A9Ten2NhYdu3axdSpU4mKimLJkiVMnDix2PPb4zVnsVgYNGgQPXr04N133+WHH37gqaeewtvbm1deeYX77ruPkSNH8vnnn/Pggw/SpUuXIq/9Gy1duhSABx54oETfw3Xr1jFo0CDq1avH9OnTycvLY9asWURHR7N3716bYg9gzJgx1K1blxkzZrB3716++uorwsLC+Ne//gXA2LFjmT59OlevXrUW7nD9Q8CVK1cYN26cdduUKVP49ttvmTx5Ms888wxnz57l448/Zt++fWzfvt2maf/EiROMHz+eKVOm8Oijj9K4cWOOHDnC0KFDadmyJW+++Sbu7u6cPn2a7du3V+g1F+fkyZOcPHmSRx55BB8fnzv9GGwUd61w/TZZs2bNGDZsGC4uLixbtownnngCRVF48sknbY5x6tQpxo4dy+OPP87EiROZM2cO9957L6tXr6Zfv342+z799NMEBgby+uuvc+7cOWbOnMlTTz3FTz/9VKrcVZrWTRPOZvjw4aqHh4d6/vx567ajR4+qBoNBvfnbWbt2bRUo8i86OlpNSUmx2XfixIkqoE6bNq3IOYtrYpsxY4aq0+lschQ2RRfav3+/CqhPPPGEzXMnTJhQoub01q1bq/7+/rfd54MPPlABdenSpaqq/tlsd/bsWZv9Nm7cqALqxo0bS31dhd+bN99802bfNm3aqO3atbN+fbvbBD179lR79uxZZPvEiRPV2rVrW78+e/asCqihoaFqenq6dfvf//53FVBbtWqlmkwm6/bx48erbm5uan5+fpFj36jwZ3PixAk1OTlZPXv2rDp79mzV3d1dDQ8Pt94K6Nmzpwqon3/+uc3zZ86cqQLq3LlzrduMRqPapUsX1cfHR83MzFRVVVUXLlyoAurMmTOt+1ksFrVPnz4qoM6ZM8fm2sv6mis8xttvv23dlpaWpnp6eqo6nU798ccfrduPHz9eotfdiBEjVEBNS0u77X6FWrdurYaFhampqanWbQcOHFD1er364IMPWrcV/gweeuihIucLDg62fn3ixAkVUGfNmmWz3xNPPKH6+PhY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "graph = ConversionGraph()\n", + "\n", + "graph.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "56bf5114-f440-4ba4-b10d-a326c931d13e", + "metadata": {}, + "source": [ + "Add Cirq $\\rightarrow$ QIR to qBraid-SDK conversion graph" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9a62940d-29f4-401c-b1e5-54bcb9fda058", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "conversion = Conversion(\"cirq\", \"qir\", cirq_to_qir)\n", + "\n", + "graph.add_conversion(conversion)\n", + "\n", + "graph.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "926f62fc-a3b3-4c35-8cd5-f326f9cd07ad", + "metadata": {}, + "source": [ + "Create Amazon Braket circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "a97cd0f5-cb2c-4b76-bbd5-67073fbe0867", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "T : |0|1|\n", + " \n", + "q0 : -H-C-\n", + " | \n", + "q1 : ---X-\n", + "\n", + "T : |0|1|\n" + ] + } + ], + "source": [ + "braket_circuit = Circuit().h(0).cnot(0, 1)\n", + "\n", + "print(braket_circuit)" + ] + }, + { + "cell_type": "markdown", + "id": "76c5e840-0b9b-4ac9-b3b2-666fff8dc1bd", + "metadata": {}, + "source": [ + "Convert Amazon Braket circuit to QIR" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7e9aeec9-13b4-473b-ae54-076fc9b9286f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "; ModuleID = 'circuit-c73622e'\n", + "source_filename = \"circuit-c73622e\"\n", + "\n", + "%Qubit = type opaque\n", + "%Result = type opaque\n", + "\n", + "define void @main() #0 {\n", + "entry:\n", + " call void @__quantum__rt__initialize(i8* null)\n", + " call void @__quantum__qis__h__body(%Qubit* null)\n", + " call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))\n", + " call void @__quantum__rt__result_record_output(%Result* null, i8* null)\n", + " call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)\n", + " ret void\n", + "}\n", + "\n", + "declare void @__quantum__rt__initialize(i8*)\n", + "\n", + "declare void @__quantum__qis__h__body(%Qubit*)\n", + "\n", + "declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)\n", + "\n", + "declare void @__quantum__rt__result_record_output(%Result*, i8*)\n", + "\n", + "attributes #0 = { \"entry_point\" \"output_labeling_schema\" \"qir_profiles\"=\"custom\" \"required_num_qubits\"=\"2\" \"required_num_results\"=\"2\" }\n", + "\n", + "!llvm.module.flags = !{!0, !1, !2, !3}\n", + "\n", + "!0 = !{i32 1, !\"qir_major_version\", i32 1}\n", + "!1 = !{i32 7, !\"qir_minor_version\", i32 0}\n", + "!2 = !{i32 1, !\"dynamic_qubit_management\", i1 false}\n", + "!3 = !{i32 1, !\"dynamic_result_management\", i1 false}\n", + "\n" + ] + } + ], + "source": [ + "qir_module = convert_to_package(braket_circuit, \"qir\", conversion_graph=graph)\n", + "\n", + "ir = str(qir_module)\n", + "\n", + "print(ir)" + ] + }, + { + "cell_type": "markdown", + "id": "6f2f571e-3f73-4a73-9491-6e2dad7e628b", + "metadata": {}, + "source": [ + "Save QIR output to `.ll` and `.bc` files in current working directory" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "34edcf3e-708b-42ec-9861-fa4924e6f24f", + "metadata": {}, + "outputs": [], + "source": [ + "dumps(qir_module)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5761c1c1-4d86-4bb9-89e9-57e4e3b184af", + "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.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qbraid_qir/rigetti_qvm_sim.ipynb b/qbraid_qir/rigetti_qvm_sim.ipynb new file mode 100644 index 0000000..191a0c9 --- /dev/null +++ b/qbraid_qir/rigetti_qvm_sim.ipynb @@ -0,0 +1,152 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# qBraid-QIR: Rigetti QVM simulation example" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Install necessary dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install qbraid-qir cirq-core azure-quantum --quiet" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Develop program with Cirq" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import cirq\n", + "\n", + "q0, q1 = cirq.LineQubit.range(2)\n", + "circuit = cirq.Circuit(cirq.H(q0), cirq.CNOT(q0, q1), cirq.measure(q0, q1))\n", + "\n", + "print(circuit)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compile program to QIR" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from qbraid_qir.cirq import cirq_to_qir\n", + "\n", + "module = cirq_to_qir(circuit, name=\"bell\")\n", + "\n", + "print(str(module))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Submit program to Rigetti via Azure Quantum Cloud" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " Note: You will have to open a terminal and run az login to make sure your Azure credentials are stored.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import azure.quantum\n", + "from azure.identity import AzureCliCredential\n", + "\n", + "workspace = azure.quantum.Workspace(\n", + " subscription_id=\"\",\n", + " resource_group=\"AzureQuantum\",\n", + " name=\"qir-demo\",\n", + " location=\"westus\",\n", + " credential=AzureCliCredential(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "job = azure.quantum.Job.from_input_data(\n", + " workspace=workspace,\n", + " name=\"qir-demo\",\n", + " provider_id=\"rigetti\",\n", + " target=\"rigetti.sim.qvm\",\n", + " input_data_format=\"qir.v1\",\n", + " output_data_format=\"microsoft.quantum-results.v1\",\n", + " input_data=module.bitcode,\n", + " input_params={\"shots\": 1, \"entryPoint\": \"main\", \"arguments\": []},\n", + ")\n", + "\n", + "info = job.details.as_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "job.get_results()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qbraid-qir", + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/qbraid_sdk/qbraid_sdk_providers.ipynb b/qbraid_sdk/qbraid_sdk_providers.ipynb index 1afe2ee..30387ea 100644 --- a/qbraid_sdk/qbraid_sdk_providers.ipynb +++ b/qbraid_sdk/qbraid_sdk_providers.ipynb @@ -148,9 +148,7 @@ }, "outputs": [], "source": [ - "braket_device = braket_provider.get_device(\n", - " \"arn:aws:braket:::device/quantum-simulator/amazon/sv1\"\n", - ")\n", + "braket_device = braket_provider.get_device(\"arn:aws:braket:::device/quantum-simulator/amazon/sv1\")\n", "\n", "braket_device.metadata()" ]