From 9b93389f3b0d1e62736c42199da4b3ebbb7ab551 Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Thu, 22 Oct 2020 23:42:41 +0300 Subject: [PATCH] Refactor RB code to allow cnot-dihedral RB on more than 2 qubits (#521) --- .../randomized_benchmarking/rb_groups.py | 3 - .../RB_dihedral_upgrade-e85c020895bcd2ed.yaml | 7 + test/rb/test_rb.py | 125 ++++++++---------- 3 files changed, 61 insertions(+), 74 deletions(-) create mode 100644 releasenotes/notes/RB_dihedral_upgrade-e85c020895bcd2ed.yaml diff --git a/qiskit/ignis/verification/randomized_benchmarking/rb_groups.py b/qiskit/ignis/verification/randomized_benchmarking/rb_groups.py index 4313a4851..7b333a53c 100644 --- a/qiskit/ignis/verification/randomized_benchmarking/rb_groups.py +++ b/qiskit/ignis/verification/randomized_benchmarking/rb_groups.py @@ -43,7 +43,6 @@ def __init__(self, group_gates, num_qubits=2): self._rb_group = CNOTDihedral self._rb_circ_type += '_cnotdihedral' self._group_gates_type = 1 - assert num_qubits <= 2, "num_qubits for CNOT-Dihedral RB should be 1 or 2" else: raise QiskitError("Unknown group or set of gates.") @@ -63,7 +62,6 @@ def iden(self, num_qubits): """Initialize an identity group element""" self._num_qubits = num_qubits if self._group_gates_type: - assert num_qubits <= 2, "num_qubits for CNOT-Dihedral RB should be 1 or 2" return CNOTDihedral(num_qubits) else: return Clifford(np.eye(2 * num_qubits)) @@ -72,7 +70,6 @@ def random(self, num_qubits, rand_seed=None): """Generate a random group element""" self._num_qubits = num_qubits if self._group_gates_type: - assert num_qubits <= 2, "num_qubits for CNOT-Dihedral RB should be 1 or 2" return random_cnotdihedral(num_qubits, seed=rand_seed) else: return random_clifford(num_qubits, seed=rand_seed) diff --git a/releasenotes/notes/RB_dihedral_upgrade-e85c020895bcd2ed.yaml b/releasenotes/notes/RB_dihedral_upgrade-e85c020895bcd2ed.yaml new file mode 100644 index 000000000..19d8fcb19 --- /dev/null +++ b/releasenotes/notes/RB_dihedral_upgrade-e85c020895bcd2ed.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + The :func:`qiskit.ignis.verification.randomized_benchmarking.randomized_benchmarking_seq` + function is now using the upgraded CNOTDihedral class + :class:`qiskit.ignis.verification.randomized_benchmarking.CNOTDihedral` + to allow CNOT-Dihedral Randomized Benchmarking on more than two qubits. diff --git a/test/rb/test_rb.py b/test/rb/test_rb.py index 99741321a..8f8871e38 100644 --- a/test/rb/test_rb.py +++ b/test/rb/test_rb.py @@ -71,37 +71,29 @@ def choose_pattern(pattern_type, nq): is_purity = True if the pattern fits for purity rb (namely, all the patterns have the same dimension: only 1-qubit or only 2-qubits). - - is_dihedral = True if the pattern fits dihedral rb - (namely only 1-qubit & 2-qubit rb) """ is_purity = True - is_dihedral = True if pattern_type == 0: res = [list(range(nq))] if nq > 2: is_purity = False - is_dihedral = False elif pattern_type == 1: if nq == 1: - return None, None, None + return None, None res = [[x] for x in range(nq)] else: if nq <= 2: - return None, None, None + return None, None shuffled_bits = list(range(nq)) random.shuffle(shuffled_bits) # split_loc = random.randint(1, nq-1) split_loc = 2 # deterministic test res = [shuffled_bits[:split_loc], shuffled_bits[split_loc:]] - # for only 1-qubit and 2-qubit RB - if (split_loc > 2) | (nq-split_loc > 2): - is_dihedral = False if 2*split_loc != nq: is_purity = False - return res, is_purity, is_dihedral + return res, is_purity @staticmethod def choose_multiplier(mult_opt, len_pattern): @@ -520,8 +512,7 @@ def test_rb(self, nq, pattern_type, multiplier_type): rb_opts['nseeds'] = 3 rb_opts['rand_seed'] = 1234 rb_opts['length_vector'] = [1, 3, 4, 7] - rb_opts['rb_pattern'], is_purity, is_dihedral = \ - self.choose_pattern(pattern_type, nq) + rb_opts['rb_pattern'], is_purity = self.choose_pattern(pattern_type, nq) # if the pattern type is not relevant for nq if rb_opts['rb_pattern'] is None: raise unittest.SkipTest('pattern type is not relevant for nq') @@ -536,9 +527,8 @@ def test_rb(self, nq, pattern_type, multiplier_type): rb_opts_cnotdihedral = rb_opts.copy() rb_opts_cnotdihedral['group_gates'] = 'CNOT-Dihedral' rb_opts_cnotdihedral_interleaved = rb_opts_cnotdihedral.copy() - if is_dihedral: - rb_opts_cnotdihedral_interleaved['interleaved_elem'], interleaved_gates = \ - self.choose_interleaved_gates(rb_opts['rb_pattern']) + rb_opts_cnotdihedral_interleaved['interleaved_elem'], interleaved_gates = \ + self.choose_interleaved_gates(rb_opts['rb_pattern']) # Choose options for purity rb # no length_multiplier rb_opts_purity['length_multiplier'] = 1 @@ -556,13 +546,12 @@ def test_rb(self, nq, pattern_type, multiplier_type): rb_original_circs, _, rb_interleaved_circs = \ rb.randomized_benchmarking_seq(**rb_opts_interleaved) # Non-Clifford cnot-dihedral RB sequences: - if is_dihedral: - rb_cnotdihedral_Z_circs, _, rb_cnotdihedral_X_circs = \ - rb.randomized_benchmarking_seq(**rb_opts_cnotdihedral) - # Non-Clifford interleaved cnot-dihedral RB sequences: - # (these circuits will not be executed to save time) - _, _, _, _, _ = \ - rb.randomized_benchmarking_seq(**rb_opts_cnotdihedral_interleaved) + rb_cnotdihedral_Z_circs, _, rb_cnotdihedral_X_circs = \ + rb.randomized_benchmarking_seq(**rb_opts_cnotdihedral) + # Non-Clifford interleaved cnot-dihedral RB sequences: + # (these circuits will not be executed to save time) + _, _, _, _, _ = \ + rb.randomized_benchmarking_seq(**rb_opts_cnotdihedral_interleaved) # Purity RB sequences: if is_purity: rb_purity_circs, _, npurity = \ @@ -578,9 +567,8 @@ def test_rb(self, nq, pattern_type, multiplier_type): result = [] result_original = [] result_interleaved = [] - if is_dihedral: - result_cnotdihedral_Z = [] - result_cnotdihedral_X = [] + result_cnotdihedral_Z = [] + result_cnotdihedral_X = [] if is_purity: result_purity = [[] for d in range(npurity)] for seed in range(rb_opts['nseeds']): @@ -598,17 +586,16 @@ def test_rb(self, nq, pattern_type, multiplier_type): backend=backend, basis_gates=basis_gates, shots=shots).result()) - if is_dihedral: - result_cnotdihedral_Z.append( - qiskit.execute(rb_cnotdihedral_Z_circs[seed], - backend=backend, - basis_gates=basis_gates, - shots=shots).result()) - result_cnotdihedral_X.append( - qiskit.execute(rb_cnotdihedral_X_circs[seed], - backend=backend, - basis_gates=basis_gates, - shots=shots).result()) + result_cnotdihedral_Z.append( + qiskit.execute(rb_cnotdihedral_Z_circs[seed], + backend=backend, + basis_gates=basis_gates, + shots=shots).result()) + result_cnotdihedral_X.append( + qiskit.execute(rb_cnotdihedral_X_circs[seed], + backend=backend, + basis_gates=basis_gates, + shots=shots).result()) if is_purity: for d in range(npurity): result_purity[d].append(qiskit.execute( @@ -638,17 +625,16 @@ def test_rb(self, nq, pattern_type, multiplier_type): 'rb_interleaved_length_%d_seed_%d' % ( circ_index, seed), 'Error: incorrect interleaved circuit name') - if is_dihedral: - self.assertEqual( - rb_cnotdihedral_Z_circs[seed][circ_index].name, - 'rb_cnotdihedral_Z_length_%d_seed_%d' % ( - circ_index, seed), - 'Error: incorrect cnotdihedral circuit name') - self.assertEqual( - rb_cnotdihedral_X_circs[seed][circ_index].name, - 'rb_cnotdihedral_X_length_%d_seed_%d' % ( - circ_index, seed), - 'Error: incorrect non-Clifford CNOT-Dihedral circuit name') + self.assertEqual( + rb_cnotdihedral_Z_circs[seed][circ_index].name, + 'rb_cnotdihedral_Z_length_%d_seed_%d' % ( + circ_index, seed), + 'Error: incorrect cnotdihedral circuit name') + self.assertEqual( + rb_cnotdihedral_X_circs[seed][circ_index].name, + 'rb_cnotdihedral_X_length_%d_seed_%d' % ( + circ_index, seed), + 'Error: incorrect non-Clifford CNOT-Dihedral circuit name') if is_purity: for d in range(npurity): name_type, _ = self.update_purity_gates( @@ -676,19 +662,18 @@ def test_rb(self, nq, pattern_type, multiplier_type): result_interleaved[seed], shots, is_interleaved=True) - if is_dihedral: - self.verify_circuit(rb_cnotdihedral_Z_circs[seed] - [circ_index], - nq, rb_opts_cnotdihedral, - vec_len, - result_cnotdihedral_Z[seed], - shots) - self.verify_circuit(rb_cnotdihedral_X_circs[seed] - [circ_index], - nq, rb_opts_cnotdihedral, - vec_len, - result_cnotdihedral_X[seed], - shots, is_cnotdihedral=True) + self.verify_circuit(rb_cnotdihedral_Z_circs[seed] + [circ_index], + nq, rb_opts_cnotdihedral, + vec_len, + result_cnotdihedral_Z[seed], + shots) + self.verify_circuit(rb_cnotdihedral_X_circs[seed] + [circ_index], + nq, rb_opts_cnotdihedral, + vec_len, + result_cnotdihedral_X[seed], + shots, is_cnotdihedral=True) if is_purity: self.verify_circuit(rb_purity_circs[seed][0] [circ_index], @@ -710,11 +695,10 @@ def test_rb(self, nq, pattern_type, multiplier_type): rb_interleaved_circs[seed][circ_index], nq, rb_opts_interleaved, interleaved_gates, vec_len) # compare the non-Clifford cnot-dihedral RB circuits - if is_dihedral: - self.compare_cnotdihedral_circuit( - rb_cnotdihedral_Z_circs[seed][circ_index], - rb_cnotdihedral_X_circs[seed][circ_index], - nq, rb_opts_cnotdihedral, vec_len) + self.compare_cnotdihedral_circuit( + rb_cnotdihedral_Z_circs[seed][circ_index], + rb_cnotdihedral_X_circs[seed][circ_index], + nq, rb_opts_cnotdihedral, vec_len) self.assertEqual(circ_index, len(rb_circs), "Error: additional circuits exist") @@ -722,11 +706,10 @@ def test_rb(self, nq, pattern_type, multiplier_type): "Error: additional interleaved circuits exist") self.assertEqual(circ_index, len(rb_interleaved_circs), "Error: additional interleaved circuits exist") - if is_dihedral: - self.assertEqual(circ_index, len(rb_cnotdihedral_Z_circs), - "Error: additional CNOTDihedral circuits exist") - self.assertEqual(circ_index, len(rb_cnotdihedral_X_circs), - "Error: additional CNOTDihedral circuits exist") + self.assertEqual(circ_index, len(rb_cnotdihedral_Z_circs), + "Error: additional CNOTDihedral circuits exist") + self.assertEqual(circ_index, len(rb_cnotdihedral_X_circs), + "Error: additional CNOTDihedral circuits exist") if is_purity: self.assertEqual(circ_index, len(rb_purity_circs), "Error: additional purity circuits exist")