def test_products(self): Cl_3 = tqc.SingleQubitClifford(3) Cl_3*Cl_3 self.assertTrue(Cl_3.idx == 3) # Pauli X self.assertTrue((Cl_3*Cl_3).idx == 0) # The identity Cl_3 = tqc.TwoQubitClifford(3) self.assertTrue(Cl_3.idx == 3) # Pauli X on q0 self.assertTrue((Cl_3*Cl_3).idx == 0) # The identity product_hash = crc32((Cl_3*Cl_3).pauli_transfer_matrix.round().astype(int)) target_hash = crc32(tqc.TwoQubitClifford(0).pauli_transfer_matrix.round().astype(int)) self.assertTrue(product_hash == target_hash)
def test_product_order(self): """ Tests that the order of multiplying matrices is the same as what is defined in numpy.dot """ Cl_528 = tqc.TwoQubitClifford(528) Cl_9230 = tqc.TwoQubitClifford(9230) Cliff_prod = Cl_528*Cl_9230 dot_prod = np.dot(Cl_528.pauli_transfer_matrix, Cl_9230.pauli_transfer_matrix) np.testing.assert_array_equal(Cliff_prod.pauli_transfer_matrix, dot_prod)
def test_two_qubit_hashtable_file(self): hash_table = tqc.get_two_qubit_clifford_hash_table() for i in test_indices_2Q: Cl = tqc.TwoQubitClifford(i) target_hash = crc32(Cl.pauli_transfer_matrix.round().astype(int)) table_idx = hash_table.index(target_hash) self.assertTrue(table_idx == i)
def test_gate_decomposition_unique_two_qubit(self): hash_table = [] for i in range(11520): CL = tqc.TwoQubitClifford(i) gate_dec = CL.gate_decomposition hash_table.append(crc32(bytes(str(gate_dec), 'utf-8'))) self.assertTrue(len(hash_table) == 11520) self.assertTrue(len(np.unique(hash_table)) == 11520)
def test_two_qubit_hashtable_constructed(self): hash_table = construct_clifford_lookuptable(tqc.TwoQubitClifford, np.arange(11520)) for i in test_indices_2Q: Cl = tqc.TwoQubitClifford(i) target_hash = crc32(Cl.pauli_transfer_matrix.round().astype(int)) table_idx = hash_table.index(target_hash) self.assertTrue(table_idx == i)
def test_get_clifford_id(self): for i in range(24): Cl = tqc.SingleQubitClifford(i) idx = tqc.get_clifford_id(Cl.pauli_transfer_matrix) self.assertTrue(idx == Cl.idx) for i in test_indices_2Q: Cl = tqc.TwoQubitClifford(i) idx = tqc.get_clifford_id(Cl.pauli_transfer_matrix) self.assertTrue(idx == Cl.idx)
def test_two_qubit_gate_decomposition(self): for idx in (test_indices_2Q): CL = tqc.TwoQubitClifford(idx) gate_dec = CL.gate_decomposition self.assertTrue(isinstance(gate_dec, list)) for g in gate_dec: self.assertTrue(isinstance(g[0], str)) if g[0] == 'CZ': self.assertTrue(g[1] == ['q0', 'q1']) else: self.assertTrue(g[1] in ['q0', 'q1'])
def test_two_qubit_gate_decomposition(self): for idx in (test_indices_2Q): CL = tqc.TwoQubitClifford(idx) gate_dec = CL.gate_decomposition print(idx, gate_dec) self.assertIsInstance(gate_dec, list) for g in gate_dec: self.assertIsInstance(g[0], str) if g[0] == 'CZ': self.assertEqual(g[1], ['q0', 'q1']) else: self.assertIn(g[1], ['q0', 'q1'])
def test_recovery_two_qubit_rb(self): cliffords = [0, 1, 50] nr_seeds = 50 for cl in cliffords: for _ in range(nr_seeds): cl_seq = rb.randomized_benchmarking_sequence_new( cl, number_of_qubits=2, max_clifford_idx=11520, interleaving_cl=None, desired_net_cl=0) for decomp in ['HZ', 'XY']: tqc.gate_decomposition = \ rb.get_clifford_decomposition(decomp) pulse_tuples_list_all = [] for i, idx in enumerate(cl_seq): pulse_tuples_list = \ tqc.TwoQubitClifford(idx).gate_decomposition pulse_tuples_list_all += pulse_tuples_list gproduct = qtp.tensor(qtp.identity(2), qtp.identity(2)) for i, cl_tup in enumerate(pulse_tuples_list_all): if cl_tup[0] == 'CZ': gproduct = self.standard_pulses[ cl_tup[0]] * gproduct else: eye_2qb = [qtp.identity(2), qtp.identity(2)] eye_2qb[int(cl_tup[1][-1])] = self.standard_pulses[ cl_tup[0]] gproduct = qtp.tensor(eye_2qb) * gproduct x = gproduct.full() / gproduct.full()[0][0] self.assertTrue( np.all((np.allclose(np.real(x), np.eye(4)), np.allclose(np.imag(x), np.zeros(4)))))
def test_inverse_two_qubit_clifford(self): for i in test_indices_2Q: Cl = tqc.TwoQubitClifford(i) Cl_inv = Cl.get_inverse() self.assertTrue((Cl_inv*Cl).idx == 0)
def rb_block(self, sp1d_idx, sp2d_idx, **kw): """ Creates simultaneous blocks of RB pulses for each task in preprocessed_task_list. Args: sp1d_idx (int): current iteration index in the 1D sweep points array sp2d_idx (int): current iteration index in the 2D sweep points array Keyword args: interleaved_gate (see docstring of parent class) """ interleaved_gate = kw.get('interleaved_gate', None) rb_block_list = [] for i, task in enumerate(self.preprocessed_task_list): param_name = 'seeds' if interleaved_gate is None else 'seeds_irb' seed_idx = sp1d_idx if self.sweep_type['seeds'] == 0 else sp2d_idx clf_idx = sp1d_idx if self.sweep_type[ 'cliffords'] == 0 else sp2d_idx seed = task['sweep_points'].get_sweep_params_property( 'values', self.sweep_type['seeds'], param_name)[seed_idx, clf_idx] clifford = task['sweep_points'].get_sweep_params_property( 'values', self.sweep_type['cliffords'], 'cliffords')[clf_idx] cl_seq = rb.randomized_benchmarking_sequence_new( clifford, number_of_qubits=2, seed=seed, max_clifford_idx=kw.get('max_clifford_idx', self.max_clifford_idx), interleaving_cl=interleaved_gate) qb_1 = task['qb_1'] qb_2 = task['qb_2'] seq_blocks = [] single_qb_gates = {qb_1: [], qb_2: []} for k, idx in enumerate(cl_seq): self.timer.checkpoint("rb_block.seq.iteration.start") pulse_tuples_list = tqc.TwoQubitClifford( idx).gate_decomposition for j, pulse_tuple in enumerate(pulse_tuples_list): if isinstance(pulse_tuple[1], list): seq_blocks.append( self.simultaneous_blocks(f'blk{k}_{j}', [ self.block_from_ops(f'blk{k}_{j}_{qbn}', gates) for qbn, gates in single_qb_gates.items() ], destroy=self.fast_mode)) single_qb_gates = {qb_1: [], qb_2: []} seq_blocks.append( self.block_from_ops( f'blk{k}_{j}_cz', f'{kw.get("cz_pulse_name", "CZ")} {qb_1} {qb_2}', )) else: qb_name = qb_1 if '0' in pulse_tuple[1] else qb_2 pulse_name = pulse_tuple[0] single_qb_gates[qb_name].append(pulse_name + ' ' + qb_name) self.timer.checkpoint("rb_block.seq.iteration.end") seq_blocks.append( self.simultaneous_blocks(f'blk{i}', [ self.block_from_ops(f'blk{i}{qbn}', gates) for qbn, gates in single_qb_gates.items() ], destroy=self.fast_mode)) rb_block_list += [ self.sequential_blocks(f'rb_block{i}', seq_blocks, destroy=self.fast_mode) ] return self.simultaneous_blocks(f'sim_rb_{sp2d_idx}_{sp1d_idx}', rb_block_list, block_align='end', destroy=self.fast_mode)