def test_delay_circuit_on_single_qubit(self): t1s = [0.10, 0.11] t2s = [0.20, 0.21] dt = 0.01 duration = 100 qc = QuantumCircuit(1) qc.delay(duration, 0) relax_pass = RelaxationNoisePass(t1s=t1s, t2s=t2s, dt=dt) actual = qi.SuperOp(relax_pass(qc)) expected = qi.SuperOp( thermal_relaxation_error(t1s[0], t2s[0], duration * dt)) self.assertEqual(expected, actual)
def test_delay_units(self, duration, unit): """Test un-scheduled delay with different units.""" t1 = 0.004 t2 = 0.008 dt = 1e-10 # 0.1 ns target_duration = 1e-5 qc = QuantumCircuit(1) qc.delay(duration, 0, unit=unit) relax_pass = RelaxationNoisePass(t1s=[t1], t2s=[t2], dt=dt) actual = qi.SuperOp(relax_pass(qc)) expected = qi.SuperOp(thermal_relaxation_error(t1, t2, target_duration)) self.assertEqual(expected, actual)
def hamiltonian_superop(ham): ham = qi.Operator(ham) dim, _ = ham.dim iden = np.eye(dim) super_op = -1j * np.kron(iden, ham.data) + 1j * np.kron( np.conj(ham.data), iden) return qi.SuperOp(super_op)
def cost_func(w): gen_m = logm(w) - w * sup_l_h.data target = qi.SuperOp(la.expm(gen_m)) if __HAS_DNORM: return dnorm(sup_s - target) # use 2-norm when old version qiskit is used. both cost functions perform comparably. return la.norm(sup_s.data - target.data)
def test_delay_circuit_on_multi_qubits(self): t1s = [0.10, 0.11] t2s = [0.20, 0.21] dt = 0.01 duration = 100 qc = QuantumCircuit(2) qc.delay(duration, 0) qc.delay(duration, 1) relax_pass = RelaxationNoisePass(t1s=t1s, t2s=t2s, dt=dt) actual = qi.SuperOp(relax_pass(qc)) noise0 = thermal_relaxation_error(t1s[0], t2s[0], duration * dt) noise1 = thermal_relaxation_error(t1s[1], t2s[1], duration * dt) expected = qi.SuperOp(noise0.expand(noise1)) self.assertEqual(expected, actual)
def _test_gate(self, gate, gates_dict, **options): """Test standard gates.""" backend = self.backend(**options) gate_cls, num_angles, has_ctrl_qubits = gates_dict[gate] circuits = self.gate_circuits(gate_cls, num_angles=num_angles, has_ctrl_qubits=has_ctrl_qubits, rng=self.RNG) label = 'final' method = backend.options.method for circuit in circuits: if method == 'density_matrix': target = qi.DensityMatrix(circuit) circuit.save_density_matrix(label=label) state_fn = qi.DensityMatrix fidelity_fn = qi.state_fidelity elif method == 'stabilizer': target = qi.Clifford(circuit) circuit.save_stabilizer(label=label) state_fn = qi.Clifford.from_dict fidelity_fn = qi.process_fidelity elif method == 'unitary': target = qi.Operator(circuit) circuit.save_unitary(label=label) state_fn = qi.Operator fidelity_fn = qi.process_fidelity elif method == 'superop': target = qi.SuperOp(circuit) circuit.save_superop(label=label) state_fn = qi.SuperOp fidelity_fn = qi.process_fidelity else: target = qi.Statevector(circuit) circuit.save_statevector(label=label) state_fn = qi.Statevector fidelity_fn = qi.state_fidelity result = backend.run(transpile(circuit, backend, optimization_level=0), shots=1).result() # Check results success = getattr(result, 'success', False) self.assertTrue(success) data = result.data(0) self.assertIn(label, data) value = state_fn(data[label]) fidelity = fidelity_fn(target, value) self.assertGreater(fidelity, 0.9999)
def test_set_superop(self, method, device, num_qubits): """Test SetSuperOp instruction""" backend = self.backend(method=method, device=device) seed = 100 label = 'state' target = qi.SuperOp(qi.random_quantum_channel(2**num_qubits, seed=seed)) circ = QuantumCircuit(num_qubits) circ.set_superop(target) circ.save_superop(label=label) # Run result = backend.run(transpile(circ, backend, optimization_level=0), shots=1).result() self.assertTrue(result.success) simdata = result.data(0) self.assertIn(label, simdata) value = qi.SuperOp(simdata[label]) self.assertEqual(value, target)
def test_save_superop(self, method, device): """Test save superop instruction""" backend = self.backend(method=method, device=device) # Test circuit SEED = 712 circ = QuantumVolume(2, seed=SEED) # Target unitary target = qi.SuperOp(circ) # Add save to circuit label = 'state' circ.save_superop(label=label) # Run result = backend.run(transpile(circ, backend, optimization_level=0), shots=1).result() self.assertTrue(result.success) simdata = result.data(0) self.assertIn(label, simdata) value = qi.SuperOp(simdata[label]) self.assertEqual(value, target)
def test_pauli_gate(self, method, device, pauli): """Test multi-qubit Pauli gate.""" pauli = qi.Pauli(pauli) circuit = QuantumCircuit(pauli.num_qubits) circuit.append(pauli, range(pauli.num_qubits)) backend = self.backend(method=method, device=device) label = 'final' if method == 'density_matrix': target = qi.DensityMatrix(circuit) circuit.save_density_matrix(label=label) state_fn = qi.DensityMatrix fidelity_fn = qi.state_fidelity elif method == 'stabilizer': target = qi.Clifford(circuit) circuit.save_stabilizer(label=label) state_fn = qi.Clifford.from_dict fidelity_fn = qi.process_fidelity elif method == 'unitary': target = qi.Operator(circuit) circuit.save_unitary(label=label) state_fn = qi.Operator fidelity_fn = qi.process_fidelity elif method == 'superop': target = qi.SuperOp(circuit) circuit.save_superop(label=label) state_fn = qi.SuperOp fidelity_fn = qi.process_fidelity else: target = qi.Statevector(circuit) circuit.save_statevector(label=label) state_fn = qi.Statevector fidelity_fn = qi.state_fidelity result = backend.run(transpile(circuit, backend, optimization_level=0), shots=1).result() # Check results success = getattr(result, 'success', False) self.assertTrue(success) data = result.data(0) self.assertIn(label, data) value = state_fn(data[label]) fidelity = fidelity_fn(target, value) self.assertGreater(fidelity, 0.9999)
def test_superop_linop(self): orig = qi.SuperOp(qi.random_quantum_channel(4, seed=10)) compat = cqi.SuperOp(orig.data) self.assertEqual(2 * compat - orig, orig) self.assertEqual(2 * orig - compat, orig)
def test_superop_eq(self): orig = qi.SuperOp(qi.random_quantum_channel(4, seed=10)) compat = cqi.SuperOp(orig.data) self.assertEqual(compat, orig) self.assertEqual(orig, compat)
def logm(w): sup_s_h = qi.SuperOp(la.expm(w * sup_l_h.data)) return la.logm((sup_s @ sup_s_h).data)
def hamiltonian_reconstruction(channels: List[Choi], pauli_labels: List[str], gate_time: float, phase_shifts: List[float] = None, shifter_label: str = 'ZI', sanity_check: bool = False)\ -> Tuple[Dict[str, np.ndarray], List[float]]: """ Extract Pauli term coefficient from quantum channel. Args: channels: quantum channels to reconstruct Hamiltonian. pauli_labels: name of Pauli terms gate_time: duration of gate phase_shifts: phase shift to unwrap 2pi uncertainty. shifter_label: pauli term to shift. sanity_check: do sanity check. Additional information: To remove 2pi uncertainty of Logm, we need decompose superop S to satisfy |M| < 2 pi. S_H = exp(w * L_H) where L_H is superop of Pauli term shift. According to BCH expansion:: M = logm(S. S_H) = logm(exp(tG).exp(w L_H)) = tG + w L_H + t*w*[G, L_H] + O(2 coms) M' = M - w L_H Then Pauli coefficients are:: b = Tr[B^dag.M'] = t*Tr[B^dag.G] + t*w*Tr[B^dag.[G, L_H]] + O(2 coms) = b_true + + t*w*Tr[B^dag.[G, L_H]] + O(2 coms) When commutator of G and L_H is zero, b = b_true. Optimizer finds w to calculate principal matrix log. """ threshold_san1 = 1e-3 threshold_san2 = 1e-1 def hamiltonian_superop(ham): ham = qi.Operator(ham) dim, _ = ham.dim iden = np.eye(dim) super_op = -1j * np.kron(iden, ham.data) + 1j * np.kron( np.conj(ham.data), iden) return qi.SuperOp(super_op) if phase_shifts is None: phase_shifts = [0 for _ in range(len(channels))] coeffs = defaultdict(list) estimated_hamiltonian_fidelities = [] for phase_shift, chan in zip(phase_shifts, channels): sup_s = qi.SuperOp(chan) sup_l_h = hamiltonian_superop(qi.Operator.from_label(shifter_label)) def logm(w): sup_s_h = qi.SuperOp(la.expm(w * sup_l_h.data)) return la.logm((sup_s @ sup_s_h).data) def cost_func(w): gen_m = logm(w) - w * sup_l_h.data target = qi.SuperOp(la.expm(gen_m)) if __HAS_DNORM: return dnorm(sup_s - target) # use 2-norm when old version qiskit is used. both cost functions perform comparably. return la.norm(sup_s.data - target.data) def log_constraint(w): return 2 * np.pi - la.norm(logm(w)) cons = ({'type': 'ineq', 'fun': log_constraint}) opt_result = opt.minimize(cost_func, x0=phase_shift, constraints=cons, method='SLSQP') w_opt = opt_result.x[0] # opt status print('w_opt = %.3e, cost_func = %.3e, generator norm = %.3e' % (w_opt, cost_func(w_opt), log_constraint(w_opt))) # sanitary check 1 sup_s_h_opt = qi.SuperOp(la.expm(w_opt * sup_l_h.data)) com_norm = la.norm((sup_s @ sup_s_h_opt - sup_s_h_opt @ sup_s).data) print('Commutator [S, S_H] norm = %.3e' % com_norm) if sanity_check: assert com_norm < threshold_san1 gen_m_opt = logm(w_opt) - w_opt * sup_l_h.data for pauli_label in pauli_labels: sup_b = hamiltonian_superop( 0.5 * qi.Operator.from_label(pauli_label).data) sup_b_dag = sup_b.adjoint() renorm = np.real(np.trace((sup_b_dag @ sup_b).data)) coeff = np.real( np.trace(np.dot(gen_m_opt, sup_b_dag.data)) / renorm) coeffs[pauli_label].append(coeff / gate_time) # sanitary check 2 reconst_ham = np.zeros((4, 4)) for pauli_label in pauli_labels: ham_op = 0.5 * qi.Operator.from_label(pauli_label).data reconst_ham = reconst_ham + coeffs[pauli_label][-1] * ham_op reconst_u = qi.Operator(la.expm(-1j * reconst_ham * gate_time)) u_fid = qi.average_gate_fidelity(chan, reconst_u) estimated_hamiltonian_fidelities.append(u_fid) if sanity_check: assert 1 - u_fid < threshold_san2 # list -> ndarray coeffs = dict(coeffs) for pauli_label in coeffs.keys(): coeffs[pauli_label] = np.array(coeffs[pauli_label]) return coeffs, estimated_hamiltonian_fidelities