From 2280ff41a208d2a96e39d0c98268b1ba5bb43196 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Sat, 23 Mar 2024 21:41:14 -0400 Subject: [PATCH 01/15] Add random circuit algo + tests --- notebooks/textbook/Random_Circuit.ipynb | 119 ++++++++++++++++++ .../algorithms/random_circuit/__init__.py | 18 +++ .../random_circuit/random_circuit.md | 7 ++ .../random_circuit/random_circuit.py | 99 +++++++++++++++ .../random_circuit/test_random_circuit.py | 57 +++++++++ 5 files changed, 300 insertions(+) create mode 100644 notebooks/textbook/Random_Circuit.ipynb create mode 100644 src/braket/experimental/algorithms/random_circuit/__init__.py create mode 100644 src/braket/experimental/algorithms/random_circuit/random_circuit.md create mode 100644 src/braket/experimental/algorithms/random_circuit/random_circuit.py create mode 100644 test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py diff --git a/notebooks/textbook/Random_Circuit.ipynb b/notebooks/textbook/Random_Circuit.ipynb new file mode 100644 index 00000000..8e5e7780 --- /dev/null +++ b/notebooks/textbook/Random_Circuit.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Random Circuit\n", + "Generates a random quantum circuit\n", + "\n", + "Random quantum circuits are important in quantum computing for several reasons:\n", + "\n", + "Rapid Circuit Generation for Testing\n", + "\n", + "Random quantum circuits are integral for quickly generating diverse and intricate test scenarios. This speed in creation allows for efficient and thorough testing of quantum computing systems, ensuring their readiness for complex tasks.\n", + "\n", + " Enhancing Benchmarking and Hardware Evaluation\n", + "\n", + "These circuits play a pivotal role in quantum benchmarking, providing a deeper and more accurate assessment of hardware quality and operational fidelity. This is crucial for ensuring that quantum systems meet the necessary standards for precision and reliability.\n", + "\n", + " Comparing Quantum Architectures\n", + "\n", + "These circuits enable objective and standardized comparisons across different quantum architectures. Such comparisons are fundamental to the advancement of quantum technology, ensuring that development is guided by accurate and impartial assessments.\n", + "\n", + " Error Identification and System Optimization\n", + "\n", + "By deploying random quantum circuits, it's possible to uncover error patterns and limitations within quantum hardware. This identification is key for continuous improvement and optimization of quantum computing systems.\n", + "\n", + " Aiding Quantum Algorithm Development\n", + "\n", + "Lastly, random quantum circuits are instrumental in the development and testing of quantum algorithms. They are particularly useful for algorithms that require diverse and complex configurations, making them an essential tool for advancing quantum computational research." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run on a local simulator" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--Circuit--\n", + "T : | 0 | 1 | 2 | 3 |4| 5 | 6 | 7 |8| 9 | 10 | 11 | 12 |13| 14 | 15 | 16 |\n", + " \n", + "q0 : -C---C------------ZZ(0.19)---ZZ(4.77)---------------------------------ISWAP----------Y-Si-----------C-------------PHASE10(2.39)-H-----------------------------------------------------\n", + " | | | | | | | \n", + "q1 : -|-I-|-GPi2(3.18)-|--------X-|--------MS(6.01, 2.11, 0.58)------------|-----------------------------PHASE01(4.86)-C-------------PHASE01(3.36)-I--MS(4.30, 5.30, 4.88)-Rx(4.12)---SWAP-\n", + " | | | | | | | | | | \n", + "q2 : -V---|------------|--------|-ZZ(4.77)-|----------------------ECR-C----|-----YY(3.63)-V-ECR----------GPi2(4.41)------------------|----------------|-------------------------------|----\n", + " | | | | | | | | | | | | \n", + "q3 : -----|------------ZZ(0.19)-|-Y--------|--------------------H-ECR-SWAP-ISWAP-|--------V-|---Rx(1.68)-----------------------------|----------------|-------------------------------SWAP-\n", + " | | | | | | | | \n", + "q4 : -----Y---------------------C----------MS(6.01, 2.11, 0.58)-------SWAP-------YY(3.63)---ECR--------------------------------------C----------------MS(4.30, 5.30, 4.88)-GPi2(5.51)------\n", + "\n", + "T : | 0 | 1 | 2 | 3 |4| 5 | 6 | 7 |8| 9 | 10 | 11 | 12 |13| 14 | 15 | 16 |\n", + "\n", + "--Counts--\n", + "Counter({'11100': 24, '11110': 11, '11010': 10, '01100': 9, '11000': 9, '01101': 8, '01110': 8, '11101': 7, '11001': 5, '11011': 4, '11111': 3, '01011': 2})\n" + ] + } + ], + "source": [ + "from braket.devices import LocalSimulator\n", + "from braket.experimental.algorithms.random_circuit import random_circuit\n", + "\n", + "\n", + "# Code here\n", + "local_simulator = LocalSimulator()\n", + "circuit = random_circuit(num_qubits=5, num_gates=30, max_operands=3, seed=42)\n", + "task = local_simulator.run(circuit, shots=100)\n", + "result = task.result()\n", + "print(\"--Circuit--\")\n", + "print(circuit)\n", + "print(\"\\n--Counts--\")\n", + "print(result.measurement_counts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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.6" + }, + "vscode": { + "interpreter": { + "hash": "5904cb9a2089448a2e1aeb5d493d227c9de33e591d7c07e4016fb81e71061a5d" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/src/braket/experimental/algorithms/random_circuit/__init__.py b/src/braket/experimental/algorithms/random_circuit/__init__.py new file mode 100644 index 00000000..edcab9e0 --- /dev/null +++ b/src/braket/experimental/algorithms/random_circuit/__init__.py @@ -0,0 +1,18 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +from braket.experimental.algorithms.random_circuit.random_circuit import ( # noqa: F401 + filter_gate_set, + random_circuit, + run_random_circuit, +) diff --git a/src/braket/experimental/algorithms/random_circuit/random_circuit.md b/src/braket/experimental/algorithms/random_circuit/random_circuit.md new file mode 100644 index 00000000..25bcc599 --- /dev/null +++ b/src/braket/experimental/algorithms/random_circuit/random_circuit.md @@ -0,0 +1,7 @@ +The `random_circuit` function generates a random quantum circuit using the Amazon Braket SDK. It's designed to construct a circuit with a specified number of qubits, instructions, and a maximum number of qubits the gate acts on. This function is useful for creating diverse quantum circuits for testing quantum algorithms or for benchmarking gate-based QPUs. + + diff --git a/src/braket/experimental/algorithms/random_circuit/random_circuit.py b/src/braket/experimental/algorithms/random_circuit/random_circuit.py new file mode 100644 index 00000000..ea9b1d60 --- /dev/null +++ b/src/braket/experimental/algorithms/random_circuit/random_circuit.py @@ -0,0 +1,99 @@ +import inspect +import math +import random + +from braket.circuits import Circuit, Instruction, gates +from braket.devices import Device +from braket.tasks import QuantumTask + + +def filter_gate_set(max_operands: int): + """ + Filters and returns Braket gate classes that require a maximum number of qubits. + + Args: + max_operands (int): Maximum number of qubits (operands) the gate acts on. + + Returns: + list: A list of gate classes constrained by the maximum number of operands. + """ + # Use list comprehension to select gate classes that meet the criteria + # Check if it's a class and if it has the 'fixed_qubit_count' method + # Check if qubit_count is an integer and if it's lower than or equal to min_qubits + selected_classes = [ + getattr(gates, cls_name) + for cls_name in dir(gates) + if isinstance((cls := getattr(gates, cls_name)), type) + and hasattr(cls, "fixed_qubit_count") + and isinstance((qubit_count := cls.fixed_qubit_count()), int) + and qubit_count <= max_operands + ] + return selected_classes + + +def random_circuit(num_qubits: int, num_gates: int, max_operands: int, seed=None) -> Circuit: + """ + Generates a random quantum circuit. + + Args: + num_qubits (int): Number of qubits in the circuit. + num_gates (int): Number of instructions (gates) in the circuit. + max_operands (int): Maximum number of qubits for each gate. + seed (Optional[int]): Random seed for reproducibility (default is None). + + Returns: + Circuit: random quantum circuit. + """ + # Set the seed if provided + if seed is not None: + random.seed(seed) + # Get filtered gate set based on the maximum number of operands (qubits) + filtered_gate_set = filter_gate_set(max_operands) + instructions = [] + for _ in range(num_gates): + # Choose a random gate from the filtered set + gate_class = random.choice(filtered_gate_set) + gate_qubits = gate_class.fixed_qubit_count() + + # Select random qubits for the gate + qubits = random.sample(range(num_qubits), gate_qubits) + + # Get the constructor's signature to determine required parameters + init_signature = inspect.signature(gate_class.__init__) + + # Calculate the number of parameters (excluding 'self') + num_params = len(init_signature.parameters) - 1 + + # Generate random parameters for the gate in the range [0, 2*pi] + params = [random.uniform(0, 2 * math.pi) for _ in range(num_params)] + + # Create the gate instance + gate = gate_class(*params) + + # Add the gate as an instruction + instructions.append(Instruction(gate, qubits)) + + # Create a circuit with the list of instructions + circuit = Circuit().add(instructions) + return circuit + + +def run_random_circuit( + circuit: Circuit, + device: Device, + shots: int = 1000, +) -> QuantumTask: + """Function to run random circuit and return measurement counts. + + Args: + circuit (Circuit): Quantum Phase Estimation circuit + device (Device): Braket device backend + shots (int) : Number of measurement shots (default is 1000). + + Returns: + QuantumTask: Task from running Quantum Phase Estimation + """ + + task = device.run(circuit, shots=shots) + + return task diff --git a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py new file mode 100644 index 00000000..cee5732d --- /dev/null +++ b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py @@ -0,0 +1,57 @@ +import pytest +from braket.circuits import Circuit +from braket.devices import LocalSimulator + +from braket.experimental.algorithms.random_circuit import ( + filter_gate_set, + random_circuit, + run_random_circuit, +) + + +def test_filter_gate_set_returns_classes(): + gate_classes = filter_gate_set(1) + assert isinstance(gate_classes, list) + assert all(isinstance(cls, type) for cls in gate_classes) + + +def test_filter_gate_set_min_qubits(): + min_qubits = 2 + gate_classes = filter_gate_set(min_qubits) + assert all(cls.fixed_qubit_count() >= min_qubits for cls in gate_classes) + + +def test_random_circuit_returns_circuit(): + circuit = random_circuit(3, 5, 1) + assert isinstance(circuit, Circuit) + + +def test_random_circuit_instruction_count(): + num_gates = 5 + circuit = random_circuit(3, num_gates, 1) + assert len(circuit.instructions) == num_gates + + +def test_random_circuit_consistency_with_seed(): + circuit1 = random_circuit(3, 5, 1, seed=123) + circuit2 = random_circuit(3, 5, 1, seed=123) + assert circuit1 == circuit2 + + +def test_random_circuit_variability_without_seed(): + circuit1 = random_circuit(3, 5, 1) + circuit2 = random_circuit(3, 5, 1) + assert circuit1 != circuit2 + + +def test_get_random_circuit_results(): + local_simulator = LocalSimulator() + circuit = random_circuit(2, 3, 1, seed=123) + circuit.probability() + + result = run_random_circuit(circuit, local_simulator, shots=0).result() + measured_probabilities = result.values[0].tolist() + expected_probabilities = [0.5, 0.5, 0, 0] + assert measured_probabilities == pytest.approx( + expected_probabilities, rel=1e-5 + ), "The measured probabilities are not within the expected tolerance." From 30e44a09b594afc2cc7bd12371236d747d7bf6d5 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Sun, 24 Mar 2024 14:42:10 -0400 Subject: [PATCH 02/15] Change seed to resolve non-contigous qubits --- .../algorithms/random_circuit/test_random_circuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py index cee5732d..af29373d 100644 --- a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py @@ -46,7 +46,7 @@ def test_random_circuit_variability_without_seed(): def test_get_random_circuit_results(): local_simulator = LocalSimulator() - circuit = random_circuit(2, 3, 1, seed=123) + circuit = random_circuit(2, 3, 1, seed=20) circuit.probability() result = run_random_circuit(circuit, local_simulator, shots=0).result() From e6321b76d7de47c6bc81fb9b35df44a42511ebb0 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Sun, 24 Mar 2024 15:17:16 -0400 Subject: [PATCH 03/15] Fix tests --- .../algorithms/random_circuit/test_random_circuit.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py index af29373d..b770f678 100644 --- a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py @@ -15,10 +15,10 @@ def test_filter_gate_set_returns_classes(): assert all(isinstance(cls, type) for cls in gate_classes) -def test_filter_gate_set_min_qubits(): - min_qubits = 2 - gate_classes = filter_gate_set(min_qubits) - assert all(cls.fixed_qubit_count() >= min_qubits for cls in gate_classes) +def test_filter_gate_set_max_qubits(): + max_qubits = 2 + gate_classes = filter_gate_set(max_qubits) + assert all(cls.fixed_qubit_count() <= max_qubits for cls in gate_classes) def test_random_circuit_returns_circuit(): From c422b9eee89a4e750592241ac8b2f0cc05e09843 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Thu, 28 Mar 2024 21:46:04 -0400 Subject: [PATCH 04/15] Address feedback: move files to auxilary section + add gate_set input --- notebooks/auxilary/Random_Circuit.ipynb | 87 +++++++++++++ notebooks/textbook/Random_Circuit.ipynb | 119 ------------------ .../random_circuit/random_circuit.md | 7 -- .../random_circuit/random_circuit.py | 99 --------------- .../random_circuit/__init__.py | 0 .../random_circuit/random_circuit.md | 7 ++ .../random_circuit/random_circuit.py | 55 ++++++++ .../random_circuit/test_random_circuit.py | 57 --------- .../random_circuit/test_random_circuit.py | 27 ++++ 9 files changed, 176 insertions(+), 282 deletions(-) create mode 100644 notebooks/auxilary/Random_Circuit.ipynb delete mode 100644 notebooks/textbook/Random_Circuit.ipynb delete mode 100644 src/braket/experimental/algorithms/random_circuit/random_circuit.md delete mode 100644 src/braket/experimental/algorithms/random_circuit/random_circuit.py rename src/braket/experimental/{algorithms => auxilary_functions}/random_circuit/__init__.py (100%) create mode 100644 src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md create mode 100644 src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py delete mode 100644 test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py create mode 100644 test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py diff --git a/notebooks/auxilary/Random_Circuit.ipynb b/notebooks/auxilary/Random_Circuit.ipynb new file mode 100644 index 00000000..4cb465e3 --- /dev/null +++ b/notebooks/auxilary/Random_Circuit.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Random Circuit\n", + "Generates a random quantum circuit\n", + "\n", + "Circuit Generation for Testing\n", + "\n", + "Random quantum circuits generator allows to create a diverse set of circuits with a variety of output probability distributions. Users can utilize random circuits to test performance of quantum simulators and QPUs. \n", + "\n", + " Benchmarking quantum compilation stacks\n", + "\n", + "Random circuits sampled from a fixed gates set (as in the example below) are often used for benchmarking performance of quantum compilation passes: circuit mapping / routing and circuit optimization passes. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run on a local simulator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from braket.devices import LocalSimulator\n", + "from braket.experimental.auxilary_functions.random_circuit import random_circuit\n", + "from braket.circuits.gates import CNot, Rx, Rz, CPhaseShift, XY\n", + "\n", + "# Code here\n", + "local_simulator = LocalSimulator()\n", + "gate_set = [CNot, Rx, Rz, CPhaseShift, XY]\n", + "circuit = random_circuit(num_qubits=5, \n", + " num_gates=30,\n", + " gate_set=gate_set,\n", + " seed=42)\n", + "task = local_simulator.run(circuit, shots=100)\n", + "result = task.result()\n", + "print(\"--Circuit--\")\n", + "print(circuit)\n", + "print(\"\\n--Counts--\")\n", + "print(result.measurement_counts)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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.6" + }, + "vscode": { + "interpreter": { + "hash": "5904cb9a2089448a2e1aeb5d493d227c9de33e591d7c07e4016fb81e71061a5d" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/textbook/Random_Circuit.ipynb b/notebooks/textbook/Random_Circuit.ipynb deleted file mode 100644 index 8e5e7780..00000000 --- a/notebooks/textbook/Random_Circuit.ipynb +++ /dev/null @@ -1,119 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Random Circuit\n", - "Generates a random quantum circuit\n", - "\n", - "Random quantum circuits are important in quantum computing for several reasons:\n", - "\n", - "Rapid Circuit Generation for Testing\n", - "\n", - "Random quantum circuits are integral for quickly generating diverse and intricate test scenarios. This speed in creation allows for efficient and thorough testing of quantum computing systems, ensuring their readiness for complex tasks.\n", - "\n", - " Enhancing Benchmarking and Hardware Evaluation\n", - "\n", - "These circuits play a pivotal role in quantum benchmarking, providing a deeper and more accurate assessment of hardware quality and operational fidelity. This is crucial for ensuring that quantum systems meet the necessary standards for precision and reliability.\n", - "\n", - " Comparing Quantum Architectures\n", - "\n", - "These circuits enable objective and standardized comparisons across different quantum architectures. Such comparisons are fundamental to the advancement of quantum technology, ensuring that development is guided by accurate and impartial assessments.\n", - "\n", - " Error Identification and System Optimization\n", - "\n", - "By deploying random quantum circuits, it's possible to uncover error patterns and limitations within quantum hardware. This identification is key for continuous improvement and optimization of quantum computing systems.\n", - "\n", - " Aiding Quantum Algorithm Development\n", - "\n", - "Lastly, random quantum circuits are instrumental in the development and testing of quantum algorithms. They are particularly useful for algorithms that require diverse and complex configurations, making them an essential tool for advancing quantum computational research." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Run on a local simulator" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--Circuit--\n", - "T : | 0 | 1 | 2 | 3 |4| 5 | 6 | 7 |8| 9 | 10 | 11 | 12 |13| 14 | 15 | 16 |\n", - " \n", - "q0 : -C---C------------ZZ(0.19)---ZZ(4.77)---------------------------------ISWAP----------Y-Si-----------C-------------PHASE10(2.39)-H-----------------------------------------------------\n", - " | | | | | | | \n", - "q1 : -|-I-|-GPi2(3.18)-|--------X-|--------MS(6.01, 2.11, 0.58)------------|-----------------------------PHASE01(4.86)-C-------------PHASE01(3.36)-I--MS(4.30, 5.30, 4.88)-Rx(4.12)---SWAP-\n", - " | | | | | | | | | | \n", - "q2 : -V---|------------|--------|-ZZ(4.77)-|----------------------ECR-C----|-----YY(3.63)-V-ECR----------GPi2(4.41)------------------|----------------|-------------------------------|----\n", - " | | | | | | | | | | | | \n", - "q3 : -----|------------ZZ(0.19)-|-Y--------|--------------------H-ECR-SWAP-ISWAP-|--------V-|---Rx(1.68)-----------------------------|----------------|-------------------------------SWAP-\n", - " | | | | | | | | \n", - "q4 : -----Y---------------------C----------MS(6.01, 2.11, 0.58)-------SWAP-------YY(3.63)---ECR--------------------------------------C----------------MS(4.30, 5.30, 4.88)-GPi2(5.51)------\n", - "\n", - "T : | 0 | 1 | 2 | 3 |4| 5 | 6 | 7 |8| 9 | 10 | 11 | 12 |13| 14 | 15 | 16 |\n", - "\n", - "--Counts--\n", - "Counter({'11100': 24, '11110': 11, '11010': 10, '01100': 9, '11000': 9, '01101': 8, '01110': 8, '11101': 7, '11001': 5, '11011': 4, '11111': 3, '01011': 2})\n" - ] - } - ], - "source": [ - "from braket.devices import LocalSimulator\n", - "from braket.experimental.algorithms.random_circuit import random_circuit\n", - "\n", - "\n", - "# Code here\n", - "local_simulator = LocalSimulator()\n", - "circuit = random_circuit(num_qubits=5, num_gates=30, max_operands=3, seed=42)\n", - "task = local_simulator.run(circuit, shots=100)\n", - "result = task.result()\n", - "print(\"--Circuit--\")\n", - "print(circuit)\n", - "print(\"\\n--Counts--\")\n", - "print(result.measurement_counts)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "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.6" - }, - "vscode": { - "interpreter": { - "hash": "5904cb9a2089448a2e1aeb5d493d227c9de33e591d7c07e4016fb81e71061a5d" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/src/braket/experimental/algorithms/random_circuit/random_circuit.md b/src/braket/experimental/algorithms/random_circuit/random_circuit.md deleted file mode 100644 index 25bcc599..00000000 --- a/src/braket/experimental/algorithms/random_circuit/random_circuit.md +++ /dev/null @@ -1,7 +0,0 @@ -The `random_circuit` function generates a random quantum circuit using the Amazon Braket SDK. It's designed to construct a circuit with a specified number of qubits, instructions, and a maximum number of qubits the gate acts on. This function is useful for creating diverse quantum circuits for testing quantum algorithms or for benchmarking gate-based QPUs. - - diff --git a/src/braket/experimental/algorithms/random_circuit/random_circuit.py b/src/braket/experimental/algorithms/random_circuit/random_circuit.py deleted file mode 100644 index ea9b1d60..00000000 --- a/src/braket/experimental/algorithms/random_circuit/random_circuit.py +++ /dev/null @@ -1,99 +0,0 @@ -import inspect -import math -import random - -from braket.circuits import Circuit, Instruction, gates -from braket.devices import Device -from braket.tasks import QuantumTask - - -def filter_gate_set(max_operands: int): - """ - Filters and returns Braket gate classes that require a maximum number of qubits. - - Args: - max_operands (int): Maximum number of qubits (operands) the gate acts on. - - Returns: - list: A list of gate classes constrained by the maximum number of operands. - """ - # Use list comprehension to select gate classes that meet the criteria - # Check if it's a class and if it has the 'fixed_qubit_count' method - # Check if qubit_count is an integer and if it's lower than or equal to min_qubits - selected_classes = [ - getattr(gates, cls_name) - for cls_name in dir(gates) - if isinstance((cls := getattr(gates, cls_name)), type) - and hasattr(cls, "fixed_qubit_count") - and isinstance((qubit_count := cls.fixed_qubit_count()), int) - and qubit_count <= max_operands - ] - return selected_classes - - -def random_circuit(num_qubits: int, num_gates: int, max_operands: int, seed=None) -> Circuit: - """ - Generates a random quantum circuit. - - Args: - num_qubits (int): Number of qubits in the circuit. - num_gates (int): Number of instructions (gates) in the circuit. - max_operands (int): Maximum number of qubits for each gate. - seed (Optional[int]): Random seed for reproducibility (default is None). - - Returns: - Circuit: random quantum circuit. - """ - # Set the seed if provided - if seed is not None: - random.seed(seed) - # Get filtered gate set based on the maximum number of operands (qubits) - filtered_gate_set = filter_gate_set(max_operands) - instructions = [] - for _ in range(num_gates): - # Choose a random gate from the filtered set - gate_class = random.choice(filtered_gate_set) - gate_qubits = gate_class.fixed_qubit_count() - - # Select random qubits for the gate - qubits = random.sample(range(num_qubits), gate_qubits) - - # Get the constructor's signature to determine required parameters - init_signature = inspect.signature(gate_class.__init__) - - # Calculate the number of parameters (excluding 'self') - num_params = len(init_signature.parameters) - 1 - - # Generate random parameters for the gate in the range [0, 2*pi] - params = [random.uniform(0, 2 * math.pi) for _ in range(num_params)] - - # Create the gate instance - gate = gate_class(*params) - - # Add the gate as an instruction - instructions.append(Instruction(gate, qubits)) - - # Create a circuit with the list of instructions - circuit = Circuit().add(instructions) - return circuit - - -def run_random_circuit( - circuit: Circuit, - device: Device, - shots: int = 1000, -) -> QuantumTask: - """Function to run random circuit and return measurement counts. - - Args: - circuit (Circuit): Quantum Phase Estimation circuit - device (Device): Braket device backend - shots (int) : Number of measurement shots (default is 1000). - - Returns: - QuantumTask: Task from running Quantum Phase Estimation - """ - - task = device.run(circuit, shots=shots) - - return task diff --git a/src/braket/experimental/algorithms/random_circuit/__init__.py b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py similarity index 100% rename from src/braket/experimental/algorithms/random_circuit/__init__.py rename to src/braket/experimental/auxilary_functions/random_circuit/__init__.py diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md new file mode 100644 index 00000000..3dcc55c4 --- /dev/null +++ b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md @@ -0,0 +1,7 @@ +The `random_circuit` function generates a random quantum circuit using the Amazon Braket SDK. +The function creates a diverse set of circuits that can be used for testing Braket SDK functionality and compiler benchmarking. + diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py new file mode 100644 index 00000000..c89a72ec --- /dev/null +++ b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py @@ -0,0 +1,55 @@ +import inspect +import math +import random +from typing import List + +from braket.circuits import Circuit, Instruction, gates +from braket.circuits.gates import CNot, H, S, T + + +def random_circuit( + num_qubits: int, num_gates: int, gate_set: List[Gate] = [CNot, S, T, H], seed=None +) -> Circuit: + """ + Generates a random quantum circuit. + + Args: + num_qubits (int): Number of qubits in the circuit. + num_gates (int): Number of instructions (gates) in the circuit. + gate_set (List[Gate]): List of basis gates for the random circuit. + seed (Optional[int]): Random seed for reproducibility (default is None). + + Returns: + Circuit: random quantum circuit. + """ + # Set the seed if provided + if seed is not None: + random.seed(seed) + + instructions = [] + for _ in range(num_gates): + gate = random.choice(gate_set) + gate_class = gate.__class__ + gate_qubits = gate_class.fixed_qubit_count() + + # Select random qubits for the gate + qubits = random.sample(range(num_qubits), gate_qubits) + + # Get the constructor's signature to determine required parameters + init_signature = inspect.signature(gate_class.__init__) + + # Calculate the number of parameters (excluding 'self') + num_params = len(init_signature.parameters) - 1 + + # Generate random parameters for the gate in the range [0, 2*pi] + params = [random.uniform(0, 2 * math.pi) for _ in range(num_params)] + + # Create the gate instance + gate = gate_class(*params) + + # Add the gate as an instruction + instructions.append(Instruction(gate, qubits)) + + # Create a circuit with the list of instructions + circuit = Circuit().add(instructions) + return circuit diff --git a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py deleted file mode 100644 index b770f678..00000000 --- a/test/unit_tests/braket/experimental/algorithms/random_circuit/test_random_circuit.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest -from braket.circuits import Circuit -from braket.devices import LocalSimulator - -from braket.experimental.algorithms.random_circuit import ( - filter_gate_set, - random_circuit, - run_random_circuit, -) - - -def test_filter_gate_set_returns_classes(): - gate_classes = filter_gate_set(1) - assert isinstance(gate_classes, list) - assert all(isinstance(cls, type) for cls in gate_classes) - - -def test_filter_gate_set_max_qubits(): - max_qubits = 2 - gate_classes = filter_gate_set(max_qubits) - assert all(cls.fixed_qubit_count() <= max_qubits for cls in gate_classes) - - -def test_random_circuit_returns_circuit(): - circuit = random_circuit(3, 5, 1) - assert isinstance(circuit, Circuit) - - -def test_random_circuit_instruction_count(): - num_gates = 5 - circuit = random_circuit(3, num_gates, 1) - assert len(circuit.instructions) == num_gates - - -def test_random_circuit_consistency_with_seed(): - circuit1 = random_circuit(3, 5, 1, seed=123) - circuit2 = random_circuit(3, 5, 1, seed=123) - assert circuit1 == circuit2 - - -def test_random_circuit_variability_without_seed(): - circuit1 = random_circuit(3, 5, 1) - circuit2 = random_circuit(3, 5, 1) - assert circuit1 != circuit2 - - -def test_get_random_circuit_results(): - local_simulator = LocalSimulator() - circuit = random_circuit(2, 3, 1, seed=20) - circuit.probability() - - result = run_random_circuit(circuit, local_simulator, shots=0).result() - measured_probabilities = result.values[0].tolist() - expected_probabilities = [0.5, 0.5, 0, 0] - assert measured_probabilities == pytest.approx( - expected_probabilities, rel=1e-5 - ), "The measured probabilities are not within the expected tolerance." diff --git a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py new file mode 100644 index 00000000..1d69cb1e --- /dev/null +++ b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py @@ -0,0 +1,27 @@ +import pytest +from braket.circuits import Circuit +from braket.devices import LocalSimulator + +from braket.experimental.auxilary_functions.random_circuit import random_circuit + + +def test_random_circuit_returns_circuit(): + circuit = random_circuit(num_qubits=3, num_gates=5, seed=1) + assert isinstance(circuit, Circuit) + + +def test_random_circuit_instruction_count(): + circuit = random_circuit(num_qubits=3, num_gates=5, seed=1) + assert len(circuit.instructions) == num_gates + + +def test_random_circuit_consistency_with_seed(): + circuit1 = random_circuit(num_qubits=3, num_gates=5, seed=1) + circuit2 = random_circuit(num_qubits=3, num_gates=5, seed=1) + assert circuit1 == circuit2 + + +def test_random_circuit_variability_without_seed(): + circuit1 = random_circuit(num_qubits=3, num_gates=5) + circuit2 = random_circuit(num_qubits=3, num_gates=5) + assert circuit1 != circuit2 From 608646ac0f864c2e7e64c84e1f3851f5570c9141 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Thu, 28 Mar 2024 22:10:17 -0400 Subject: [PATCH 05/15] Fix tests --- .../auxilary_functions/random_circuit/__init__.py | 6 +----- .../random_circuit/random_circuit.py | 10 +++++----- .../random_circuit/test_random_circuit.py | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py index edcab9e0..580ec8c8 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py +++ b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py @@ -11,8 +11,4 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from braket.experimental.algorithms.random_circuit.random_circuit import ( # noqa: F401 - filter_gate_set, - random_circuit, - run_random_circuit, -) +from braket.experimental.auxilary_functions.random_circuit import random_circuit diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py index c89a72ec..2fb29c56 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py +++ b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py @@ -3,7 +3,7 @@ import random from typing import List -from braket.circuits import Circuit, Instruction, gates +from braket.circuits import Circuit, Gate, Instruction from braket.circuits.gates import CNot, H, S, T @@ -30,13 +30,13 @@ def random_circuit( for _ in range(num_gates): gate = random.choice(gate_set) gate_class = gate.__class__ - gate_qubits = gate_class.fixed_qubit_count() + gate_qubits = gate.fixed_qubit_count() # Select random qubits for the gate qubits = random.sample(range(num_qubits), gate_qubits) # Get the constructor's signature to determine required parameters - init_signature = inspect.signature(gate_class.__init__) + init_signature = inspect.signature(gate.__init__) # Calculate the number of parameters (excluding 'self') num_params = len(init_signature.parameters) - 1 @@ -45,10 +45,10 @@ def random_circuit( params = [random.uniform(0, 2 * math.pi) for _ in range(num_params)] # Create the gate instance - gate = gate_class(*params) + g = gate(*params) # Add the gate as an instruction - instructions.append(Instruction(gate, qubits)) + instructions.append(Instruction(g, qubits)) # Create a circuit with the list of instructions circuit = Circuit().add(instructions) diff --git a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py index 1d69cb1e..d43a0cb8 100644 --- a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py @@ -1,8 +1,7 @@ import pytest from braket.circuits import Circuit -from braket.devices import LocalSimulator -from braket.experimental.auxilary_functions.random_circuit import random_circuit +from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit def test_random_circuit_returns_circuit(): @@ -11,7 +10,8 @@ def test_random_circuit_returns_circuit(): def test_random_circuit_instruction_count(): - circuit = random_circuit(num_qubits=3, num_gates=5, seed=1) + num_gates = 5 + circuit = random_circuit(num_qubits=3, num_gates=num_gates, seed=1) assert len(circuit.instructions) == num_gates From 3fff1f2c916ad1b4924a99ef93cf8c1d820de7d2 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Thu, 28 Mar 2024 22:20:03 -0400 Subject: [PATCH 06/15] fix more tests --- .../experimental/auxilary_functions/random_circuit/__init__.py | 2 +- .../auxilary_functions/random_circuit/random_circuit.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py index 580ec8c8..4ce9b16f 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py +++ b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py @@ -11,4 +11,4 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from braket.experimental.auxilary_functions.random_circuit import random_circuit +from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py index 2fb29c56..bebe8cc1 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py +++ b/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py @@ -29,7 +29,6 @@ def random_circuit( instructions = [] for _ in range(num_gates): gate = random.choice(gate_set) - gate_class = gate.__class__ gate_qubits = gate.fixed_qubit_count() # Select random qubits for the gate From 140801e215e8d9c4a19e108551226e451ff7f29a Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Thu, 28 Mar 2024 22:24:17 -0400 Subject: [PATCH 07/15] remove unused imports --- .../experimental/auxilary_functions/random_circuit/__init__.py | 2 -- .../auxilary_functions/random_circuit/test_random_circuit.py | 1 - 2 files changed, 3 deletions(-) diff --git a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py index 4ce9b16f..c6e7e329 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py +++ b/src/braket/experimental/auxilary_functions/random_circuit/__init__.py @@ -10,5 +10,3 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. - -from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit diff --git a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py index d43a0cb8..117ddf0e 100644 --- a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py @@ -1,4 +1,3 @@ -import pytest from braket.circuits import Circuit from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit From a4bbe3c0d23c9191690bb1b466c404039297d9f8 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Thu, 28 Mar 2024 22:32:24 -0400 Subject: [PATCH 08/15] Fix notebook import --- notebooks/auxilary/Random_Circuit.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notebooks/auxilary/Random_Circuit.ipynb b/notebooks/auxilary/Random_Circuit.ipynb index 4cb465e3..b1cbc44e 100644 --- a/notebooks/auxilary/Random_Circuit.ipynb +++ b/notebooks/auxilary/Random_Circuit.ipynb @@ -32,7 +32,7 @@ "outputs": [], "source": [ "from braket.devices import LocalSimulator\n", - "from braket.experimental.auxilary_functions.random_circuit import random_circuit\n", + "from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit\n", "from braket.circuits.gates import CNot, Rx, Rz, CPhaseShift, XY\n", "\n", "# Code here\n", From f41322654b90ce8dc19e434f786fbf4f4d41ef00 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Fri, 29 Mar 2024 12:17:43 -0400 Subject: [PATCH 09/15] Feedback: minor changes --- .../Random_Circuit.ipynb | 4 ++-- .../__init__.py | 2 ++ .../auxiliary_functions/random_circuit/__init__.py | 14 ++++++++++++++ .../random_circuit/random_circuit.md | 0 .../random_circuit/random_circuit.py | 12 ++++++++---- .../random_circuit/test_random_circuit.py | 2 +- 6 files changed, 27 insertions(+), 7 deletions(-) rename notebooks/{auxilary => auxiliary_functions}/Random_Circuit.ipynb (86%) rename src/braket/experimental/{auxilary_functions/random_circuit => auxiliary_functions}/__init__.py (92%) create mode 100644 src/braket/experimental/auxiliary_functions/random_circuit/__init__.py rename src/braket/experimental/{auxilary_functions => auxiliary_functions}/random_circuit/random_circuit.md (100%) rename src/braket/experimental/{auxilary_functions => auxiliary_functions}/random_circuit/random_circuit.py (83%) rename test/unit_tests/braket/experimental/{auxilary_functions => auxiliary_functions}/random_circuit/test_random_circuit.py (89%) diff --git a/notebooks/auxilary/Random_Circuit.ipynb b/notebooks/auxiliary_functions/Random_Circuit.ipynb similarity index 86% rename from notebooks/auxilary/Random_Circuit.ipynb rename to notebooks/auxiliary_functions/Random_Circuit.ipynb index b1cbc44e..6b641b82 100644 --- a/notebooks/auxilary/Random_Circuit.ipynb +++ b/notebooks/auxiliary_functions/Random_Circuit.ipynb @@ -10,7 +10,7 @@ "\n", "Circuit Generation for Testing\n", "\n", - "Random quantum circuits generator allows to create a diverse set of circuits with a variety of output probability distributions. Users can utilize random circuits to test performance of quantum simulators and QPUs. \n", + "Random quantum circuit generator allows creation of a diverse set of circuits with a variety of output probability distributions. Users can utilize random circuits to test performance of quantum simulators and QPUs. \n", "\n", " Benchmarking quantum compilation stacks\n", "\n", @@ -32,7 +32,7 @@ "outputs": [], "source": [ "from braket.devices import LocalSimulator\n", - "from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit\n", + "from braket.experimental.auxiliary_functions.random_circuit import random_circuit\n", "from braket.circuits.gates import CNot, Rx, Rz, CPhaseShift, XY\n", "\n", "# Code here\n", diff --git a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py b/src/braket/experimental/auxiliary_functions/__init__.py similarity index 92% rename from src/braket/experimental/auxilary_functions/random_circuit/__init__.py rename to src/braket/experimental/auxiliary_functions/__init__.py index c6e7e329..89da7f0f 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/__init__.py +++ b/src/braket/experimental/auxiliary_functions/__init__.py @@ -10,3 +10,5 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. + +from .random_circuit import random_circuit diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py b/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py new file mode 100644 index 00000000..89da7f0f --- /dev/null +++ b/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py @@ -0,0 +1,14 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +from .random_circuit import random_circuit diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md similarity index 100% rename from src/braket/experimental/auxilary_functions/random_circuit/random_circuit.md rename to src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md diff --git a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py similarity index 83% rename from src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py rename to src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py index bebe8cc1..24fa9168 100644 --- a/src/braket/experimental/auxilary_functions/random_circuit/random_circuit.py +++ b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py @@ -1,14 +1,14 @@ import inspect import math import random -from typing import List +from typing import Optional -from braket.circuits import Circuit, Gate, Instruction +from braket.circuits import Circuit, Instruction from braket.circuits.gates import CNot, H, S, T def random_circuit( - num_qubits: int, num_gates: int, gate_set: List[Gate] = [CNot, S, T, H], seed=None + num_qubits: int, num_gates: int, gate_set=None, seed: Optional[int] = None ) -> Circuit: """ Generates a random quantum circuit. @@ -16,7 +16,7 @@ def random_circuit( Args: num_qubits (int): Number of qubits in the circuit. num_gates (int): Number of instructions (gates) in the circuit. - gate_set (List[Gate]): List of basis gates for the random circuit. + gate_set (List[Gate]): List of basis gates for the random circuit (default is None). seed (Optional[int]): Random seed for reproducibility (default is None). Returns: @@ -26,6 +26,10 @@ def random_circuit( if seed is not None: random.seed(seed) + # Default gate_set (Clifford + T) if gate_set is None + if not gate_set: + gate_set = [CNot, S, T, H] + instructions = [] for _ in range(num_gates): gate = random.choice(gate_set) diff --git a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py similarity index 89% rename from test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py rename to test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py index 117ddf0e..0f568445 100644 --- a/test/unit_tests/braket/experimental/auxilary_functions/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py @@ -1,6 +1,6 @@ from braket.circuits import Circuit -from braket.experimental.auxilary_functions.random_circuit.random_circuit import random_circuit +from braket.experimental.auxiliary_functions.random_circuit import random_circuit def test_random_circuit_returns_circuit(): From 40787f2b93269cdff377a4f64bed813ccfa1e832 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Fri, 29 Mar 2024 12:23:55 -0400 Subject: [PATCH 10/15] fix linters --- src/braket/experimental/auxiliary_functions/__init__.py | 2 +- .../experimental/auxiliary_functions/random_circuit/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/braket/experimental/auxiliary_functions/__init__.py b/src/braket/experimental/auxiliary_functions/__init__.py index 89da7f0f..31f716cf 100644 --- a/src/braket/experimental/auxiliary_functions/__init__.py +++ b/src/braket/experimental/auxiliary_functions/__init__.py @@ -11,4 +11,4 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from .random_circuit import random_circuit +from .random_circuit import random_circuit # noqa: F401 diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py b/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py index 89da7f0f..31f716cf 100644 --- a/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py +++ b/src/braket/experimental/auxiliary_functions/random_circuit/__init__.py @@ -11,4 +11,4 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -from .random_circuit import random_circuit +from .random_circuit import random_circuit # noqa: F401 From 6e90f552f00409436e1dbd2b39875fd69b45e816 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Fri, 29 Mar 2024 12:27:30 -0400 Subject: [PATCH 11/15] Update .md metadata --- .../auxiliary_functions/random_circuit/random_circuit.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md index 3dcc55c4..498ebe24 100644 --- a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md +++ b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md @@ -2,6 +2,6 @@ The `random_circuit` function generates a random quantum circuit using the Amazo The function creates a diverse set of circuits that can be used for testing Braket SDK functionality and compiler benchmarking. From 711c3420caaaa12d45a09d105c765dbb3e442536 Mon Sep 17 00:00:00 2001 From: Yaroslav Kharkov Date: Fri, 29 Mar 2024 13:11:09 -0400 Subject: [PATCH 12/15] Increase code coverage --- .../random_circuit/test_random_circuit.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py index 0f568445..b43a3af5 100644 --- a/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py @@ -1,4 +1,5 @@ from braket.circuits import Circuit +from braket.circuits.gates import XY, CNot, CPhaseShift, H, Rx, Ry, Rz, S, T from braket.experimental.auxiliary_functions.random_circuit import random_circuit @@ -24,3 +25,15 @@ def test_random_circuit_variability_without_seed(): circuit1 = random_circuit(num_qubits=3, num_gates=5) circuit2 = random_circuit(num_qubits=3, num_gates=5) assert circuit1 != circuit2 + + +def test_custom_gate_set(): + gate_set = [CNot, H, S, T, Rx, Ry, Rz, XY, CPhaseShift] + circuit = random_circuit(num_qubits=3, num_gates=5, gate_set=gate_set, seed=1) + + gate_from_gate_set = [] + for instr in circuit.instructions: + gate_class = instr.operator.__class__ + gate_from_gate_set.append(gate_class in gate_set) + + assert all(gate_from_gate_set) From 5ac64bcdb6417cccb7cc195385a3712214ba6d08 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:28:20 -0400 Subject: [PATCH 13/15] Update README, minor cleanup --- README.md | 5 ++ .../auxiliary_functions/Random_Circuit.ipynb | 56 +++++++++++++------ .../random_circuit/random_circuit.md | 2 +- .../random_circuit/test_random_circuit.py | 2 +- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2c9cd560..ce79c854 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,11 @@ Running notebooks locally requires additional dependencies located in [notebooks | Quantum PCA | [Quantum_Principal_Component_Analysis.ipynb](notebooks/advanced_algorithms/Quantum_Principal_Component_Analysis.ipynb) | [He2022](https://ieeexplore.ieee.org/document/9669030) | | QMC | [Quantum_Computing_Quantum_Monte_Carlo.ipynb](notebooks/advanced_algorithms/Quantum_Computing_Quantum_Monte_Carlo.ipynb) | [Motta2018](https://wires.onlinelibrary.wiley.com/doi/10.1002/wcms.1364), [Peruzzo2014](https://www.nature.com/articles/ncomms5213) | + +| Auxiliary functions | Notebook | +| ----- | ----- | +| Random circuit generator | [Random_Circuit.ipynb](notebooks/auxiliary_functions/Random_Circuit.ipynb) | + --- ### Community repos diff --git a/notebooks/auxiliary_functions/Random_Circuit.ipynb b/notebooks/auxiliary_functions/Random_Circuit.ipynb index 6b641b82..40705164 100644 --- a/notebooks/auxiliary_functions/Random_Circuit.ipynb +++ b/notebooks/auxiliary_functions/Random_Circuit.ipynb @@ -6,15 +6,16 @@ "metadata": {}, "source": [ "# Random Circuit\n", - "Generates a random quantum circuit\n", "\n", - "Circuit Generation for Testing\n", + "Generates random quantum circuits using the Amazon Braket SDK.\n", "\n", - "Random quantum circuit generator allows creation of a diverse set of circuits with a variety of output probability distributions. Users can utilize random circuits to test performance of quantum simulators and QPUs. \n", + "### Circuit Generation for Testing\n", "\n", - " Benchmarking quantum compilation stacks\n", + "Random quantum circuits allow creation of a diverse set of circuits with a variety of output probability distributions. Users can utilize random circuits to test performance of quantum simulators and QPUs. \n", "\n", - "Random circuits sampled from a fixed gates set (as in the example below) are often used for benchmarking performance of quantum compilation passes: circuit mapping / routing and circuit optimization passes. " + "### Benchmarking quantum compilation stacks\n", + "\n", + "Random circuits sampled from a fixed gate set (as in the example below) are often used for benchmarking performance of quantum compilation passes, such as circuit mapping, routing, or circuit optimization passes. " ] }, { @@ -27,13 +28,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--Circuit--\n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │\n", + " ┌───┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ \n", + "q0 : ───●────────────────┤ X ├──────────────┤ XY(0.19) ├───────┤ Rz(4.77) ├───────┤ Rz(0.58) ├─┤ XY(4.59) ├─┤ XY(0.50) ├───●────┤ Rz(5.37) ├───┤ Rz(1.44) ├───────┤ Rz(1.33) ├────────────────────────────────────\n", + " │ └─┬─┘ └────┬─────┘ └──────────┘ └──────────┘ └────┬─────┘ └────┬─────┘ │ └──────────┘ └──────────┘ └──────────┘ \n", + " │ ┌──────────┐ │ ┌──────────┐ │ ┌───┐ ┌──────────┐ ┌──────────┐ │ │ ┌─┴─┐ ┌─────────────┐ ┌───┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ \n", + "q1 : ───┼───┤ Rx(0.88) ├───┼───┤ Rx(3.18) ├──────┼───────┤ X ├─┤ XY(2.82) ├───────┤ Rx(6.01) ├──────┼────────────┼───────┤ X ├─┤ PHASE(2.33) ├──────────────┤ X ├─┤ XY(2.90) ├───────┤ XY(4.12) ├─┤ PHASE(1.66) ├─\n", + " │ └──────────┘ │ └──────────┘ │ └─┬─┘ └────┬─────┘ └──────────┘ │ │ └───┘ └──────┬──────┘ └─┬─┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ \n", + " ┌─┴─┐ │ │ │ │ ┌────┴─────┐ │ ┌───┐ │ ┌──────────┐ │ │ ┌────┴─────┐ │ \n", + "q2 : ─┤ X ├────────────────┼─────────────────────┼─────────┼────────┼─────────●────────────────┤ XY(4.59) ├──────┼───────┤ X ├────────●────────┤ Rx(4.41) ├───┼────────┼─────────●───┤ XY(4.12) ├────────┼────────\n", + " └───┘ │ │ │ │ │ └──────────┘ │ └─┬─┘ └──────────┘ │ │ │ └──────────┘ │ \n", + " │ ┌────┴─────┐ │ ┌────┴─────┐ │ ┌──────────┐ ┌────┴─────┐ │ │ │ ┌─┴─┐ │ \n", + "q3 : ──────────────────────┼────────────────┤ XY(0.19) ├───┼───┤ XY(2.82) ├───┼───┤ Rx(2.14) ├──────────────┤ XY(0.50) ├───●──────────────────────────────────┼────────┼───────┤ X ├─────────────────────●────────\n", + " │ └──────────┘ │ └──────────┘ │ └──────────┘ └──────────┘ │ │ └───┘ \n", + " │ │ ┌─┴─┐ ┌──────────┐ ┌──────────┐ │ ┌────┴─────┐ ┌──────────┐ ┌──────────┐ \n", + "q4 : ──────────────────────●───────────────────────────────●────────────────┤ X ├─┤ Rz(5.56) ├─┤ Rz(1.21) ├───────────────────────────────────────────────────●───┤ XY(2.90) ├───────┤ Rz(1.38) ├──┤ Rx(3.39) ├───\n", + " └───┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ \n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │\n", + "\n", + "--Counts--\n", + "Counter({'01011': 34, '00011': 21, '00001': 13, '00111': 10, '01001': 10, '01010': 3, '00000': 2, '00101': 2, '01000': 2, '10000': 1, '00010': 1, '11010': 1})\n" + ] + } + ], "source": [ - "from braket.devices import LocalSimulator\n", - "from braket.experimental.auxiliary_functions.random_circuit import random_circuit\n", "from braket.circuits.gates import CNot, Rx, Rz, CPhaseShift, XY\n", + "from braket.devices import LocalSimulator\n", + "from braket.experimental.auxiliary_functions import random_circuit\n", "\n", "# Code here\n", "local_simulator = LocalSimulator()\n", @@ -49,13 +78,6 @@ "print(\"\\n--Counts--\")\n", "print(result.measurement_counts)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -74,7 +96,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.4" }, "vscode": { "interpreter": { diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md index 498ebe24..b1b16637 100644 --- a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md +++ b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.md @@ -2,6 +2,6 @@ The `random_circuit` function generates a random quantum circuit using the Amazo The function creates a diverse set of circuits that can be used for testing Braket SDK functionality and compiler benchmarking. diff --git a/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py index b43a3af5..a38e267b 100644 --- a/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py +++ b/test/unit_tests/braket/experimental/auxiliary_functions/random_circuit/test_random_circuit.py @@ -1,7 +1,7 @@ from braket.circuits import Circuit from braket.circuits.gates import XY, CNot, CPhaseShift, H, Rx, Ry, Rz, S, T -from braket.experimental.auxiliary_functions.random_circuit import random_circuit +from braket.experimental.auxiliary_functions import random_circuit def test_random_circuit_returns_circuit(): From 06736597448c5d4a6118b390e6262ec3db54edc4 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:31:31 -0400 Subject: [PATCH 14/15] Add type hint --- .../auxiliary_functions/random_circuit/random_circuit.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py index 24fa9168..83cd4e20 100644 --- a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py +++ b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py @@ -1,14 +1,17 @@ import inspect import math import random -from typing import Optional +from typing import List, Optional -from braket.circuits import Circuit, Instruction +from braket.circuits import Circuit, Gate, Instruction from braket.circuits.gates import CNot, H, S, T def random_circuit( - num_qubits: int, num_gates: int, gate_set=None, seed: Optional[int] = None + num_qubits: int, + num_gates: int, + gate_set: Optional[List[Gate]] = None, + seed: Optional[int] = None, ) -> Circuit: """ Generates a random quantum circuit. From 657a96b4af83be5291afdb46bfb2f18cea3e0c76 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:32:32 -0400 Subject: [PATCH 15/15] Update docstring --- .../auxiliary_functions/random_circuit/random_circuit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py index 83cd4e20..0f5d0af6 100644 --- a/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py +++ b/src/braket/experimental/auxiliary_functions/random_circuit/random_circuit.py @@ -19,7 +19,8 @@ def random_circuit( Args: num_qubits (int): Number of qubits in the circuit. num_gates (int): Number of instructions (gates) in the circuit. - gate_set (List[Gate]): List of basis gates for the random circuit (default is None). + gate_set (Optional[List[Gate]]): List of basis gates for the random circuit + (default is None). seed (Optional[int]): Random seed for reproducibility (default is None). Returns: