Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gate Decomposition(#90) Added and Tested #106

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 55 additions & 10 deletions qiskit_braket_provider/providers/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
GateModelSimulatorParadigmProperties,
)
from braket.devices import LocalSimulator

from numpy import pi

from qiskit import QuantumCircuit
from qiskit.circuit import Instruction as QiskitInstruction
from qiskit.circuit import Measure, Parameter
Expand Down Expand Up @@ -99,21 +101,25 @@


qiskit_gate_names_to_braket_gates: Dict[str, Callable] = {
"u": lambda theta, phi, lam: [
gates.Rz(lam),
gates.Rx(pi / 2),
gates.Rz(theta),
gates.Rx(-pi / 2),
gates.Rz(phi),
],
"u1": lambda lam: [gates.Rz(lam)],
"u2": lambda phi, lam: [gates.Rz(lam), gates.Ry(pi / 2), gates.Rz(phi)],
"u3": lambda theta, phi, lam: [
gates.Rz(lam),
gates.Rx(pi / 2),
gates.Rz(theta),
gates.Rx(-pi / 2),
gates.Ry(theta),
gates.Rz(phi),
gates.PhaseShift((lam + phi) * (0.5)),
gates.X(),
gates.PhaseShift((lam + phi) * (0.5)),
gates.X(),
],
"u": lambda theta, phi, lam: [
gates.Rz(lam),
gates.Ry(theta),
gates.Rz(phi),
gates.PhaseShift((lam + phi) * (0.5)),
gates.X(),
gates.PhaseShift((lam + phi) * (0.5)),
gates.X(),
],
"p": lambda angle: [gates.PhaseShift(angle)],
"cp": lambda angle: [gates.CPhaseShift(angle)],
Expand Down Expand Up @@ -352,6 +358,39 @@ def aws_device_to_target(device: AwsDevice) -> Target:
return target


def decompose_fully(circuit: QuantumCircuit) -> QuantumCircuit:
"""Returns a qiskit circuit which is decomposed as much as possible.
Args:
circuit (QuantumCircuit): Qiskit Quantum Cricuit

Returns:
QuantumCircuit: decomposed Qiskit circuit
"""
old_circuit, decomposed_circuit = None, circuit
translatable_gates = set(qiskit_gate_names_to_braket_gates.keys())
translatable_gates = translatable_gates.union({"measure", "barrier", "reset"})
# decompose quantum circuit
while not (
{gate.name for gate, _, _ in decomposed_circuit.data}.issubset(
translatable_gates
)
and not (old_circuit == decomposed_circuit)
):
old_circuit = decomposed_circuit
decomposed_circuit = old_circuit.decompose()
if old_circuit == decomposed_circuit:
break
# correct global_phase shifts which might have occurred
global_phase = decomposed_circuit.global_phase
if global_phase != 0:
decomposed_circuit.p(global_phase, range(decomposed_circuit.num_qubits))
decomposed_circuit.x(range(decomposed_circuit.num_qubits))
decomposed_circuit.p(global_phase, range(decomposed_circuit.num_qubits))
decomposed_circuit.x(range(decomposed_circuit.num_qubits))
decomposed_circuit.global_phase = 0
return decomposed_circuit


def convert_qiskit_to_braket_circuit(circuit: QuantumCircuit) -> Circuit:
"""Return a Braket quantum circuit from a Qiskit quantum circuit.
Args:
Expand All @@ -361,6 +400,12 @@ def convert_qiskit_to_braket_circuit(circuit: QuantumCircuit) -> Circuit:
Circuit: Braket circuit
"""
quantum_circuit = Circuit()
translatable_gates = set(qiskit_gate_names_to_braket_gates.keys()).union(
{"measure", "barrier", "reset"}
)
if not ({gate.name for gate, _, _ in circuit.data}.issubset(translatable_gates)):
circuit = decompose_fully(circuit)
# handle qiskit to braket conversion
for qiskit_gates in circuit.data:
name = qiskit_gates[0].name
if name == "measure":
Expand Down
2 changes: 1 addition & 1 deletion qiskit_braket_provider/providers/braket_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def run(
tasks = []
try:
for circuit in circuits:
task: Union[LocalQuantumTask] = self._aws_device.run(
task: LocalQuantumTask = self._aws_device.run(
task_specification=circuit, shots=shots
)
tasks.append(task)
Expand Down
227 changes: 220 additions & 7 deletions tests/providers/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,231 @@
from unittest import TestCase

from braket.circuits import Circuit, FreeParameter, observables
from braket.devices import LocalSimulator

import numpy as np
from qiskit import QuantumCircuit

from qiskit import QuantumCircuit, execute, BasicAer
from qiskit.circuit import Parameter
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.opflow import I, Z, X
from qiskit.circuit.library.standard_gates import (
HGate,
CHGate,
IGate,
PhaseGate,
CPhaseGate,
RGate,
RXGate,
CRXGate,
RXXGate,
RYGate,
CRYGate,
RYYGate,
RZGate,
CRZGate,
RZZGate,
RZXGate,
XXMinusYYGate,
XXPlusYYGate,
ECRGate,
SGate,
SdgGate,
CSGate,
CSdgGate,
SwapGate,
CSwapGate,
iSwapGate,
SXGate,
SXdgGate,
CSXGate,
DCXGate,
TGate,
TdgGate,
UGate,
CUGate,
U1Gate,
CU1Gate,
U2Gate,
U3Gate,
CU3Gate,
XGate,
CXGate,
CCXGate,
C3SXGate,
RCCXGate,
RC3XGate,
YGate,
CYGate,
ZGate,
CZGate,
CCZGate,
)

from qiskit_braket_provider.providers.adapter import (
convert_qiskit_to_braket_circuit,
decompose_fully,
qiskit_gate_name_to_braket_gate_mapping,
qiskit_gate_names_to_braket_gates,
qiskit_to_braket_gate_names_mapping,
wrap_circuits_in_verbatim_box,
)

_EPS = 1e-10 # global variable used to chop very small numbers to zero

list_list = [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]

standard_gates = [
IGate(),
SXGate(),
XGate(),
CXGate(),
RZGate(Parameter("λ")),
RGate(Parameter("ϴ"), Parameter("φ")),
C3SXGate(),
CCXGate(),
DCXGate(),
CHGate(),
CPhaseGate(Parameter("ϴ")),
CRXGate(Parameter("ϴ")),
CRYGate(Parameter("ϴ")),
CRZGate(Parameter("ϴ")),
CSwapGate(),
CSXGate(),
CUGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ"), Parameter("γ")),
CU1Gate(Parameter("λ")),
CU3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
CYGate(),
CZGate(),
CCZGate(),
HGate(),
PhaseGate(Parameter("ϴ")),
RCCXGate(),
RC3XGate(),
RXGate(Parameter("ϴ")),
RXXGate(Parameter("ϴ")),
RYGate(Parameter("ϴ")),
RYYGate(Parameter("ϴ")),
RZZGate(Parameter("ϴ")),
RZXGate(Parameter("ϴ")),
XXMinusYYGate(Parameter("ϴ")),
XXPlusYYGate(Parameter("ϴ")),
ECRGate(),
SGate(),
SdgGate(),
CSGate(),
CSdgGate(),
SwapGate(),
iSwapGate(),
SXdgGate(),
TGate(),
TdgGate(),
UGate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
U1Gate(Parameter("λ")),
U2Gate(Parameter("φ"), Parameter("λ")),
U3Gate(Parameter("ϴ"), Parameter("φ"), Parameter("λ")),
YGate(),
ZGate(),
]


class TestAdapter(TestCase):
"""Tests adapter."""

def test_state_preparation_01(self):
"""Tests state_preparation handling of Adapter"""
input_state_vector = np.array([np.sqrt(3) / 2, np.sqrt(2) * complex(1, 1) / 4])

qiskit_circuit = QuantumCircuit(1)
qiskit_circuit.prepare_state(input_state_vector, 0)

braket_circuit = convert_qiskit_to_braket_circuit(qiskit_circuit)
braket_circuit.state_vector() # pylint: disable=no-member
result = LocalSimulator().run(braket_circuit)
output_state_vector = np.array(result.result().values[0])

self.assertTrue(
(
np.sqrt(
np.sum(np.square(np.abs(input_state_vector - output_state_vector)))
)
< _EPS
)
)

def test_state_preparation_00(self):
"""Tests state_preparation handling of Adapter"""
input_state_vector = np.array([1 / np.sqrt(2), -1 / np.sqrt(2)])

qiskit_circuit = QuantumCircuit(1)
qiskit_circuit.prepare_state(input_state_vector, 0)

braket_circuit = convert_qiskit_to_braket_circuit(qiskit_circuit)
braket_circuit.state_vector() # pylint: disable=no-member
result = LocalSimulator().run(braket_circuit)
output_state_vector = np.array(result.result().values[0])

self.assertTrue(
(
np.sqrt(
np.sum(np.square(np.abs(input_state_vector - output_state_vector)))
)
< _EPS
)
)

def test_u_gate(self):
"""Tests adapter conversion of u gate"""
qiskit_circuit = QuantumCircuit(1)
device = LocalSimulator()
for _ in range(8):
qiskit_circuit.u(np.pi / 2, np.pi / 3, np.pi / 4, 0)

backend = BasicAer.get_backend("statevector_simulator")
job = execute(qiskit_circuit, backend)

braket_circuit = convert_qiskit_to_braket_circuit(qiskit_circuit)
braket_circuit.state_vector() # pylint: disable=no-member

braket_output = device.run(braket_circuit).result().values[0]
qiskit_output = np.array(job.result().get_statevector(qiskit_circuit))

self.assertTrue(
np.sqrt(np.sum(np.square(np.abs(braket_output - qiskit_output)))) < _EPS
)

def test_standard_gate_decomp(self):
"""Tests adapter decomposition of all standard gates to forms that can be translated"""
translatable = True
for standard_gate in standard_gates:
circuit = QuantumCircuit(5)
circuit.append(standard_gate, list_list[standard_gate.num_qubits])
decomp_circuit = decompose_fully(circuit)
for simple_gate in decomp_circuit.data:
translatable = (
translatable
and simple_gate[0].name in qiskit_gate_names_to_braket_gates
)
self.assertTrue(translatable)

def test_exponential_gate_decomp_00(self):
"""Tests adapter decomposition of exponential gates to forms that can be translated"""
translatable = True

operator = (Z ^ Z) - 0.1 * (X ^ I)
evo = PauliEvolutionGate(operator, time=0.2)

# plug it into a circuit
circuit = QuantumCircuit(2)
circuit.append(evo, range(2))
decomp_circuit = decompose_fully(circuit)
for simple_gate in decomp_circuit.data:
translatable = (
translatable
and simple_gate[0].name in qiskit_gate_names_to_braket_gates
)
self.assertTrue(translatable)

def test_mappers(self):
"""Tests mappers."""
self.assertEqual(
Expand Down Expand Up @@ -46,15 +255,19 @@ def test_convert_parametric_qiskit_to_braket_circuit(self):
Circuit() # pylint: disable=no-member
.rz(0, FreeParameter("θ"))
.rz(0, FreeParameter("λ"))
.rx(0, np.pi / 2)
.rz(0, FreeParameter("θ"))
.rx(0, -np.pi / 2)
.ry(0, FreeParameter("θ"))
.rz(0, FreeParameter("φ"))
.phaseshift(0, (FreeParameter("φ") + FreeParameter("λ")) * (0.5))
.x(0)
.phaseshift(0, (FreeParameter("φ") + FreeParameter("λ")) * (0.5))
.x(0)
.rz(0, np.pi)
.rx(0, np.pi / 2)
.rz(0, FreeParameter("θ"))
.rx(0, -np.pi / 2)
.ry(0, FreeParameter("θ"))
.rz(0, FreeParameter("φ"))
.phaseshift(0, (FreeParameter("φ") + np.pi) * (0.5))
.x(0)
.phaseshift(0, (FreeParameter("φ") + np.pi) * (0.5))
.x(0)
)

self.assertEqual(braket_circuit, braket_circuit_ans)
Expand Down