diff --git a/qiskit/ignis/verification/randomized_benchmarking/circuits.py b/qiskit/ignis/verification/randomized_benchmarking/circuits.py index e91ee38d8..d29166f25 100644 --- a/qiskit/ignis/verification/randomized_benchmarking/circuits.py +++ b/qiskit/ignis/verification/randomized_benchmarking/circuits.py @@ -123,7 +123,7 @@ def check_pattern(pattern, is_purity=False, interleaved_elem=None): return pattern_flat, np.max(pattern_flat).item(), np.max(pattern_dim) -def handle_interleaved_elem(interleaved_elem, rb_group): +def handle_interleaved_elem(interleaved_elem, rb_group, keep_original_interleaved_elem): """ Handle the various types of the interleaved element Args: @@ -132,6 +132,8 @@ def handle_interleaved_elem(interleaved_elem, rb_group): List[qiskit.quantum_info.operators.symplectic.Clifford]. not None only for interleaved RB rb_group (RBgroup): the relevant RBgroup class object + keep_original_interleaved_elem (bool): whether to transform the + original element to group element or keep as it is Raises: ValueError: if interleaved_elem does not have one of the relevant types, @@ -147,27 +149,35 @@ def handle_interleaved_elem(interleaved_elem, rb_group): if interleaved_elem is None: return None - else: - for elem in interleaved_elem: - if isinstance(elem, (QuantumCircuit, Instruction)): - num_qubits = elem.num_qubits - qc = elem - elem = rb_group.iden(num_qubits) - elem = elem.from_circuit(qc) - if (isinstance(elem, qiskit.quantum_info.operators.symplectic.clifford.Clifford) - and group_gates_type == 0) or (isinstance(elem, CNOTDihedral) - and group_gates_type == 1): - interleaved_elem_list.append(elem) - else: - raise ValueError("Invalid interleaved element type.") - - if not isinstance(elem, QuantumCircuit) and \ - not isinstance(elem, - qiskit.quantum_info.operators.symplectic.clifford.Clifford) \ - and not isinstance(elem, CNOTDihedral): - raise ValueError("Invalid interleaved element type. " - "interleaved_elem should be a list of QuantumCircuit," - "or a list of Clifford / CNOTDihedral objects") + for elem in interleaved_elem: + group_elem = elem + if isinstance(elem, (QuantumCircuit, Instruction)): + num_qubits = elem.num_qubits + group_elem = rb_group.iden(num_qubits) + group_elem = group_elem.from_circuit(elem) + if not (isinstance(group_elem, qiskit.quantum_info.operators.symplectic.clifford.Clifford) + and group_gates_type == 0) and \ + not (isinstance(group_elem, CNOTDihedral) and group_gates_type == 1): + raise ValueError("Invalid interleaved element type.") + + if not isinstance(group_elem, QuantumCircuit) and \ + not isinstance(group_elem, + qiskit.quantum_info.operators.symplectic.clifford.Clifford) \ + and not isinstance(group_elem, CNOTDihedral): + raise ValueError("Invalid interleaved element type. " + "interleaved_elem should be a list of QuantumCircuit," + "or a list of Clifford / CNOTDihedral objects") + + circuit_elem = rb_group.to_circuit(group_elem) + if keep_original_interleaved_elem: + if isinstance(elem, Instruction): + circuit_elem = QuantumCircuit(elem.num_qubits) + circuit_elem.append(elem, range(elem.num_qubits)) + elif isinstance(elem, QuantumCircuit): + circuit_elem = elem + + interleaved_elem_list.append((circuit_elem, group_elem)) + return interleaved_elem_list @@ -202,6 +212,7 @@ def randomized_benchmarking_seq(nseeds: int = 1, Union[List[QuantumCircuit], List[Instruction], List[qiskit.quantum_info.operators.symplectic.Clifford], List[CNOTDihedral]]] = None, + keep_original_interleaved_elem: Optional[bool] = True, is_purity: bool = False, group_gates: Optional[str] = None, rand_seed: Optional[Union[int, RandomState]] = None) -> \ @@ -267,6 +278,10 @@ def randomized_benchmarking_seq(nseeds: int = 1, The lengths of the lists should be equal to the length of the lists in ``rb_pattern``. + keep_original_interleaved_elem: whether to keep the original interleaved + element as it is when adding it to the RB circuits or to transform + it to a standard representation via group elements + is_purity: ``True`` only for purity randomized benchmarking (default is ``False``). @@ -401,7 +416,9 @@ def randomized_benchmarking_seq(nseeds: int = 1, rb_circ_type = rb_group.rb_circ_type() # Handle various types of the interleaved element - interleaved_elem = handle_interleaved_elem(interleaved_elem, rb_group) + interleaved_elem = handle_interleaved_elem(interleaved_elem, + rb_group, + keep_original_interleaved_elem) # initialization: rb sequences circuits = [[] for e in range(nseeds)] @@ -446,9 +463,9 @@ def randomized_benchmarking_seq(nseeds: int = 1, new_elmnt = rb_group.random(rb_q_num, rand_seed) Elmnts[rb_pattern_index] = rb_group.compose( Elmnts[rb_pattern_index], new_elmnt) - general_circ += replace_q_indices( + general_circ.compose(replace_q_indices( rb_group.to_circuit(new_elmnt), - rb_pattern[rb_pattern_index], qr) + rb_pattern[rb_pattern_index], qr), inplace=True) # add a barrier general_circ.barrier( @@ -460,21 +477,20 @@ def randomized_benchmarking_seq(nseeds: int = 1, rb_group.compose( Elmnts_interleaved[rb_pattern_index], new_elmnt) - interleaved_circ += replace_q_indices( + interleaved_circ.compose(replace_q_indices( rb_group.to_circuit( new_elmnt), - rb_pattern[rb_pattern_index], qr) + rb_pattern[rb_pattern_index], qr), inplace=True) Elmnts_interleaved[rb_pattern_index] = \ rb_group.compose( Elmnts_interleaved[rb_pattern_index], - interleaved_elem[rb_pattern_index]) + interleaved_elem[rb_pattern_index][1]) # add a barrier - interleaved rb interleaved_circ.barrier( *[qr[x] for x in rb_pattern[rb_pattern_index]]) - interleaved_circ += replace_q_indices( - rb_group.to_circuit( - interleaved_elem[rb_pattern_index]), - rb_pattern[rb_pattern_index], qr) + interleaved_circ.compose(replace_q_indices( + interleaved_elem[rb_pattern_index][0], + rb_pattern[rb_pattern_index], qr), inplace=True) # add a barrier - interleaved rb interleaved_circ.barrier( *[qr[x] for x in rb_pattern[rb_pattern_index]]) @@ -493,30 +509,31 @@ def randomized_benchmarking_seq(nseeds: int = 1, if (elmnts_index+1) == length_vector[length_index]: # circ for rb: circ = QuantumCircuit(qr, cr) - circ += general_circ + circ.compose(general_circ, inplace=True) # circ_interleaved for interleaved rb: circ_interleaved = QuantumCircuit(qr, cr) - circ_interleaved += interleaved_circ + circ_interleaved.compose(interleaved_circ, inplace=True) for (rb_pattern_index, rb_q_num) in enumerate(pattern_sizes): inv_circuit = rb_group.inverse(Elmnts[rb_pattern_index]) - circ += replace_q_indices(inv_circuit, - rb_pattern[rb_pattern_index], qr) + circ.compose(replace_q_indices(inv_circuit, + rb_pattern[rb_pattern_index], qr), + inplace=True) # calculate the inverse and produce the circuit # for interleaved rb if interleaved_elem is not None: inv_circuit_interleaved = rb_group.inverse( Elmnts_interleaved[rb_pattern_index]) - circ_interleaved += replace_q_indices( + circ_interleaved.compose(replace_q_indices( inv_circuit_interleaved, - rb_pattern[rb_pattern_index], qr) + rb_pattern[rb_pattern_index], qr), inplace=True) # Circuits for purity rb if is_purity: circ_purity = [[] for d in range(npurity)] for d in range(npurity): circ_purity[d] = QuantumCircuit(qr, cr) - circ_purity[d] += circ + circ_purity[d].compose(circ, inplace=True) circ_purity[d].name = rb_circ_type + '_purity_' ind_d = d purity_qubit_num = 0 @@ -564,8 +581,8 @@ def randomized_benchmarking_seq(nseeds: int = 1, cnotdihedral_circ.barrier(qr[qb]) cnotdihedral_interleaved_circ.h(qr[qb]) cnotdihedral_interleaved_circ.barrier(qr[qb]) - cnotdihedral_circ += circ - cnotdihedral_interleaved_circ += circ_interleaved + cnotdihedral_circ.compose(circ, inplace=True) + cnotdihedral_interleaved_circ.compose(circ_interleaved, inplace=True) for _, qb in enumerate(qlist_flat): cnotdihedral_circ.barrier(qr[qb]) cnotdihedral_circ.h(qr[qb]) diff --git a/test/rb/test_rb.py b/test/rb/test_rb.py index bb7faa858..e58ebeec9 100644 --- a/test/rb/test_rb.py +++ b/test/rb/test_rb.py @@ -720,7 +720,8 @@ def test_rb(self, nq, pattern_type, multiplier_type): def test_interleaved_randomized_benchmarking_seq_1q_clifford_gates(self, gate): """interleaved 1Q Clifford gates in RB""" rb_original_circs, _, rb_interleaved_circs = rb.randomized_benchmarking_seq( - nseeds=1, length_vector=[5], rb_pattern=[[0]], interleaved_elem=[gate[0]]) + nseeds=1, length_vector=[5], rb_pattern=[[0]], + interleaved_elem=[gate[0]], keep_original_interleaved_elem=False) # Verify the generated sequences rb_opts = {} rb_opts['nseeds'] = 1 @@ -746,7 +747,8 @@ def test_interleaved_randomized_benchmarking_seq_1q_clifford_gates(self, gate): def test_interleaved_randomized_benchmarking_seq_2q_clifford_gates(self, gate): """interleaved 2Q Clifford gates in RB""" rb_original_circs, _, rb_interleaved_circs = rb.randomized_benchmarking_seq( - nseeds=1, length_vector=[5], rb_pattern=[[0, 1]], interleaved_elem=[gate]) + nseeds=1, length_vector=[5], rb_pattern=[[0, 1]], + interleaved_elem=[gate], keep_original_interleaved_elem=False) # Verify the generated sequences rb_opts = {} rb_opts['nseeds'] = 1 @@ -775,6 +777,7 @@ def test_interleaved_randomized_benchmarking_seq_1q_cnotdihedral_gates(self, gat rb_cnotdihedral_interleaved_Z_circs, rb_cnotdihedral_interleaved_X_circs = \ rb.randomized_benchmarking_seq(nseeds=1, length_vector=[5], rb_pattern=[[0]], interleaved_elem=[gate], + keep_original_interleaved_elem=False, group_gates='CNOT-Dihedral') # Verify the generated sequences rb_opts = {} @@ -815,6 +818,7 @@ def test_interleaved_randomized_benchmarking_seq_2q_cnotdihedral_gates(self): rb_cnotdihedral_interleaved_Z_circs, rb_cnotdihedral_interleaved_X_circs = \ rb.randomized_benchmarking_seq(nseeds=1, length_vector=[5], rb_pattern=[[0, 1]], interleaved_elem=[gate], + keep_original_interleaved_elem=False, group_gates='CNOT-Dihedral') # Verify the generated sequences rb_opts = {} @@ -865,7 +869,9 @@ def test_interleaved_randomized_benchmarking_seq_random_clifford_gates(self, num rb_original_circs, _, rb_interleaved_circs = rb.randomized_benchmarking_seq( nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], - interleaved_elem=[clifford]) + interleaved_elem=[clifford], + keep_original_interleaved_elem=False + ) self.assertEqual(rb_original_circs[seed][circ_index].name, 'rb_length_%d_seed_%d' % (circ_index, seed), 'Error: incorrect circuit name') @@ -879,7 +885,9 @@ def test_interleaved_randomized_benchmarking_seq_random_clifford_gates(self, num rb_original_circs, _, rb_interleaved_circs = rb.randomized_benchmarking_seq( nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], - interleaved_elem=[test_circ]) + interleaved_elem=[test_circ], + keep_original_interleaved_elem=False + ) self.assertEqual(rb_original_circs[seed][circ_index].name, 'rb_length_%d_seed_%d' % (circ_index, seed), 'Error: incorrect circuit name') @@ -893,7 +901,9 @@ def test_interleaved_randomized_benchmarking_seq_random_clifford_gates(self, num rb_original_circs, _, rb_interleaved_circs = rb.randomized_benchmarking_seq( nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], - interleaved_elem=[test_gates]) + interleaved_elem=[test_gates], + keep_original_interleaved_elem=False + ) self.assertEqual(rb_original_circs[seed][circ_index].name, 'rb_length_%d_seed_%d' % (circ_index, seed), 'Error: incorrect circuit name') @@ -927,6 +937,7 @@ def test_interleaved_randomized_benchmarking_seq_random_cnotdihedral_gates(self, rb.randomized_benchmarking_seq(nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], interleaved_elem=[elem], + keep_original_interleaved_elem=False, group_gates='CNOT-Dihedral') self.assertEqual(rb_cnotdihedral_Z_circs[seed][circ_index].name, 'rb_cnotdihedral_Z_length_%d_seed_%d' % (circ_index, seed), @@ -956,6 +967,7 @@ def test_interleaved_randomized_benchmarking_seq_random_cnotdihedral_gates(self, rb.randomized_benchmarking_seq(nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], interleaved_elem=[test_circ], + keep_original_interleaved_elem=False, group_gates='CNOT-Dihedral') self.assertEqual(rb_cnotdihedral_Z_circs[seed][circ_index].name, 'rb_cnotdihedral_Z_length_%d_seed_%d' % (circ_index, seed), @@ -985,6 +997,7 @@ def test_interleaved_randomized_benchmarking_seq_random_cnotdihedral_gates(self, rb.randomized_benchmarking_seq(nseeds=1, length_vector=[5], rb_pattern=[list(range(num_qubits))], interleaved_elem=[test_gates], + keep_original_interleaved_elem=False, group_gates='CNOT-Dihedral') self.assertEqual(rb_cnotdihedral_Z_circs[seed][circ_index].name, 'rb_cnotdihedral_Z_length_%d_seed_%d' % (circ_index, seed),