Skip to content

Commit

Permalink
Add random circuit generator + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ykharkov committed Mar 24, 2024
1 parent 5f8904d commit 3c50644
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 0 deletions.
119 changes: 119 additions & 0 deletions notebooks/textbook/Random_Circuit.ipynb
Original file line number Diff line number Diff line change
@@ -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",
"<u>Rapid Circuit Generation for Testing</u>\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",
"<u> Enhancing Benchmarking and Hardware Evaluation</u>\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",
"<u> Comparing Quantum Architectures</u>\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",
"<u> Error Identification and System Optimization</u>\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",
"<u> Aiding Quantum Algorithm Development</u>\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
}
18 changes: 18 additions & 0 deletions src/braket/experimental/algorithms/random_circuit/__init__.py
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
@@ -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.

<!--
[metadata-name]: Random Quantum Circuit Generator
[metadata-tags]: Textbook
[metadata-url]: https://github.com/aws-samples/amazon-braket-algorithm-library/tree/main/src/braket/experimental/algorithms/random_circuit
-->
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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."

0 comments on commit 3c50644

Please sign in to comment.