Skip to content

Commit

Permalink
Update randomised transpiler-equivalence test strategies (#7980)
Browse files Browse the repository at this point in the history
This commit updates the strategies used to do the randomised testing of
transpiler equivalence, having three main effects:

1. The "pre-transpilation" circuit is now run on an Aer backend without
   any transpilation at all, making the test truer to its name.
   Previously `execute` was used which secretly performs a transpilation
   internally.  This was accompanied by a small change to the set of
   gates, to ensure only those that are directly supported by Aer are
   used.

2. The strategies used for drawing gates are simplified into (mostly) a
   single rule that draws a gate from a set, and populates it.  This is
   just tidying up - it unifies the logic for drawing a gate into one
   strategy rather than several.

3. The tests are updated to avoid using deprecated behaviour (e.g.
   back-referencing a register from a bit) or features (e.g. various old
   gate classes, and the old Aer `qasm_simulator`).

Point 1 in this list is also a fix to recent randomised testing
failures; since the tests were updated in ff4ee1b to call `backend.run`
directly (rather than `execute`) in the second run of each circuit,
when Hypothesis was drawing `None` as the backend in conjunction with a
gate Aer didn't know how to simulate (e.g. `CRZGate`), Aer would raise
an exception.  Previously this behaviour was hidden by the internal call
to `transpile` inherent in `execute`, and was a logic error in the test
suite, rather than in Terra.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
jakelishman and mergify[bot] authored Apr 25, 2022
1 parent 4211b5b commit 27ef0d6
Showing 1 changed file with 36 additions and 103 deletions.
139 changes: 36 additions & 103 deletions test/randomized/test_transpiler_equivalence.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

import hypothesis.strategies as st

from qiskit import execute, transpile, Aer
from qiskit import transpile, Aer
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit import Measure, Reset, Gate, Barrier
from qiskit.test.mock import (
Expand Down Expand Up @@ -106,18 +106,18 @@

settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", default_profile))

oneQ_gates = [HGate, IGate, SGate, SdgGate, TGate, TdgGate, XGate, YGate, ZGate, Reset]
twoQ_gates = [CXGate, CYGate, CZGate, SwapGate, CHGate]
threeQ_gates = [CCXGate, CSwapGate]

oneQ_oneP_gates = [U1Gate, RXGate, RYGate, RZGate]
oneQ_twoP_gates = [U2Gate]
oneQ_threeP_gates = [U3Gate]

twoQ_oneP_gates = [CRZGate, RZZGate, CU1Gate]
twoQ_threeP_gates = [CU3Gate]

oneQ_oneC_gates = [Measure]
BASE_INSTRUCTIONS = {
# Key is (n_qubits, n_clbits, n_params). All gates here should be directly known by Aer so they
# can be simulated without an initial transpile (whether that's via `execute` or not).
(1, 0, 0): [HGate, IGate, SGate, SdgGate, TGate, TdgGate, XGate, YGate, ZGate, Reset],
(2, 0, 0): [CXGate, CYGate, CZGate, SwapGate],
(3, 0, 0): [CCXGate, CSwapGate],
(1, 0, 1): [PhaseGate, RXGate, RYGate, RZGate],
(1, 0, 3): [UGate],
(2, 0, 1): [RZZGate, CPhaseGate],
(2, 0, 4): [CUGate],
(1, 1, 0): [Measure],
}
variadic_gates = [Barrier]


Expand Down Expand Up @@ -253,13 +253,12 @@ class QCircuitMachine(RuleBasedStateMachine):
a random backend with a random optimization level and simulate both the
initial and the transpiled circuits to verify that their counts are the
same.
"""

qubits = Bundle("qubits")
clbits = Bundle("clbits")

backend = Aer.get_backend("qasm_simulator")
backend = Aer.get_backend("aer_simulator")
max_qubits = int(backend.configuration().n_qubits / 2)

def __init__(self):
Expand All @@ -285,92 +284,24 @@ def add_creg(self, n):

# Gates of various shapes

@rule(gate=st.sampled_from(oneQ_gates), qarg=qubits)
def add_1q_gate(self, gate, qarg):
"""Append a random 1q gate on a random qubit."""
self.qc.append(gate(), [qarg], [])

@rule(
gate=st.sampled_from(twoQ_gates),
qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
)
def add_2q_gate(self, gate, qargs):
"""Append a random 2q gate across two random qubits."""
self.qc.append(gate(), qargs)

@rule(
gate=st.sampled_from(threeQ_gates),
qargs=st.lists(qubits, max_size=3, min_size=3, unique=True),
)
def add_3q_gate(self, gate, qargs):
"""Append a random 3q gate across three random qubits."""
self.qc.append(gate(), qargs)

@rule(
gate=st.sampled_from(oneQ_oneP_gates),
qarg=qubits,
param=st.floats(
allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi
),
)
def add_1q1p_gate(self, gate, qarg, param):
"""Append a random 1q gate with 1 random float parameter."""
self.qc.append(gate(param), [qarg])

@rule(
gate=st.sampled_from(oneQ_twoP_gates),
qarg=qubits,
params=st.lists(
st.floats(allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi),
min_size=2,
max_size=2,
),
)
def add_1q2p_gate(self, gate, qarg, params):
"""Append a random 1q gate with 2 random float parameters."""
self.qc.append(gate(*params), [qarg])

@rule(
gate=st.sampled_from(oneQ_threeP_gates),
qarg=qubits,
params=st.lists(
st.floats(allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi),
min_size=3,
max_size=3,
),
)
def add_1q3p_gate(self, gate, qarg, params):
"""Append a random 1q gate with 3 random float parameters."""
self.qc.append(gate(*params), [qarg])

@rule(
gate=st.sampled_from(twoQ_oneP_gates),
qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
param=st.floats(
allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi
),
)
def add_2q1p_gate(self, gate, qargs, param):
"""Append a random 2q gate with 1 random float parameter."""
self.qc.append(gate(param), qargs)

@rule(
gate=st.sampled_from(twoQ_threeP_gates),
qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
params=st.lists(
st.floats(allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi),
min_size=3,
max_size=3,
),
)
def add_2q3p_gate(self, gate, qargs, params):
"""Append a random 2q gate with 3 random float parameters."""
self.qc.append(gate(*params), qargs)

@rule(gate=st.sampled_from(oneQ_oneC_gates), qarg=qubits, carg=clbits)
def add_1q1c_gate(self, gate, qarg, carg):
"""Append a random 1q, 1c gate."""
self.qc.append(gate(), [qarg], [carg])
@precondition(lambda self: self.qc.num_qubits > 0 and self.qc.num_clbits > 0)
@rule(n_arguments=st.sampled_from(sorted(BASE_INSTRUCTIONS.keys())), data=st.data())
def add_gate(self, n_arguments, data):
"""Append a random fixed gate to the circuit."""
n_qubits, n_clbits, n_params = n_arguments
gate_class = data.draw(st.sampled_from(BASE_INSTRUCTIONS[n_qubits, n_clbits, n_params]))
qubits = data.draw(st.lists(self.qubits, min_size=n_qubits, max_size=n_qubits, unique=True))
clbits = data.draw(st.lists(self.clbits, min_size=n_clbits, max_size=n_clbits, unique=True))
params = data.draw(
st.lists(
st.floats(
allow_nan=False, allow_infinity=False, min_value=-10 * pi, max_value=10 * pi
),
min_size=n_params,
max_size=n_params,
)
)
self.qc.append(gate_class(*params), qubits, clbits)

@precondition(lambda self: self.enable_variadic)
@rule(gate=st.sampled_from(variadic_gates), qargs=st.lists(qubits, min_size=1, unique=True))
Expand All @@ -382,7 +313,7 @@ def add_variQ_gate(self, gate, qargs):
@rule(carg=clbits, data=st.data())
def add_c_if_last_gate(self, carg, data):
"""Modify the last gate to be conditional on a classical register."""
creg = carg.register
creg = self.qc.find_bit(carg).registers[0][0]
val = data.draw(st.integers(min_value=0, max_value=2 ** len(creg) - 1))

last_gate = self.qc.data[-1]
Expand Down Expand Up @@ -418,7 +349,9 @@ def equivalent_transpile(self, conf):

shots = 4096

aer_counts = execute(self.qc, backend=self.backend, shots=shots).result().get_counts()
# Note that there's no transpilation here, which is why the gates are limited to only ones
# that Aer supports natively.
aer_counts = self.backend.run(self.qc, shots=shots).result().get_counts()

try:
xpiled_qc = transpile(
Expand Down

0 comments on commit 27ef0d6

Please sign in to comment.