def test_save_expval_var_cptp_pauli(self, pauli): """Test Pauli expval_var for stabilizer circuit""" SUPPORTED_METHODS = [ 'density_matrix', 'density_matrix_gpu', 'density_matrix_thrust' ] SEED = 5832 opts = self.BACKEND_OPTS.copy() if opts.get('method') in SUPPORTED_METHODS: oper = qi.Operator(qi.Operator(qi.Pauli(pauli))) # CPTP channel test circuit channel = qi.random_quantum_channel(4, seed=SEED) state_circ = QuantumCircuit(2) state_circ.append(channel, range(2)) state = qi.DensityMatrix(state_circ) expval = state.expectation_value(oper).real variance = state.expectation_value(oper**2).real - expval**2 target = [expval, variance] # Snapshot circuit circ = transpile(state_circ, self.SIMULATOR) circ.save_expectation_value_variance(oper, [0, 1], label='expval') qobj = assemble(circ) result = self.SIMULATOR.run(qobj, **opts).result() self.assertTrue(result.success) value = result.data(0)['expval'] self.assertTrue(allclose(value, target))
def test_save_unitary(self): """Test save unitary for instruction""" SUPPORTED_METHODS = [ 'automatic', 'unitary', 'unitary_gpu', 'unitary_thrust' ] # Stabilizer test circuit circ = transpile(QuantumVolume(3), self.SIMULATOR) # Target unitary target = qi.Operator(circ) # Add save to circuit save_key = 'state' circ.save_unitary(save_key) # Run opts = self.BACKEND_OPTS.copy() qobj = assemble(circ, self.SIMULATOR) result = self.SIMULATOR.run(qobj, **opts).result() method = opts.get('method', 'automatic') if method not in SUPPORTED_METHODS: self.assertFalse(result.success) else: self.assertTrue(result.success) data = result.data(0) self.assertIn(save_key, data) value = qi.Operator(result.data(0)[save_key]) self.assertEqual(value, target)
def test_weyl_unitaries_random_circuit(self): """Weyl decomposition for a random two-qubit circuit.""" theta = pi / 9 epsilon = 5 delta = -1 eta = 0.2 qr = QuantumRegister(2, "qr") circuit = QuantumCircuit(qr) # random two-qubit circuit. circuit.rzx(theta, 0, 1) circuit.rzz(epsilon, 0, 1) circuit.rz(eta, 0) circuit.swap(1, 0) circuit.h(0) circuit.rzz(delta, 1, 0) circuit.swap(0, 1) circuit.cx(1, 0) circuit.swap(0, 1) circuit.h(1) circuit.rxx(theta, 0, 1) circuit.ryy(theta, 1, 0) circuit.ecr(0, 1) unitary_circuit = qi.Operator(circuit).data dag = circuit_to_dag(circuit) pass_ = EchoRZXWeylDecomposition(self.inst_map) after = dag_to_circuit(pass_.run(dag)) unitary_after = qi.Operator(after).data self.assertTrue(np.allclose(unitary_circuit, unitary_after))
def test_save_expval_var_cptp_pauli(self, method, device, pauli): """Test Pauli expval_var for stabilizer circuit""" SEED = 5832 oper = qi.Operator(qi.Operator(qi.Pauli(pauli))) channel = qi.random_quantum_channel(4, seed=SEED) circ = QuantumCircuit(2) circ.append(channel, range(2)) qubits = [0, 1] self._test_save_expval(circ, oper, qubits, True, method=method, device=device)
def test_weyl_decomposition_gate_angles(self): """Check the number and angles of the RZX gates for different gates""" thetas = [pi / 9, 2.1, -0.2] qr = QuantumRegister(2, "qr") circuit_rxx = QuantumCircuit(qr) circuit_rxx.rxx(thetas[0], qr[1], qr[0]) circuit_ryy = QuantumCircuit(qr) circuit_ryy.ryy(thetas[1], qr[0], qr[1]) circuit_rzz = QuantumCircuit(qr) circuit_rzz.rzz(thetas[2], qr[1], qr[0]) circuits = [circuit_rxx, circuit_ryy, circuit_rzz] for circuit in circuits: unitary_circuit = qi.Operator(circuit).data dag = circuit_to_dag(circuit) pass_ = EchoRZXWeylDecomposition(self.inst_map) after = dag_to_circuit(pass_.run(dag)) dag_after = circuit_to_dag(after) unitary_after = qi.Operator(after).data # check whether the unitaries are equivalent. self.assertTrue(np.allclose(unitary_circuit, unitary_after)) # check whether the after circuit has the correct number of rzx gates. self.assertRZXgates(unitary_circuit, after) alpha = TwoQubitWeylDecomposition(unitary_circuit).a rzx_angles = [] for node in dag_after.two_qubit_ops(): if node.name == "rzx": rzx_angle = node.op.params[0] # check whether the absolute values of the RZX gate angles # are equivalent to the corresponding Weyl parameter. self.assertAlmostEqual(np.abs(rzx_angle), alpha) rzx_angles.append(rzx_angle) # check whether the angles of every RZX gate pair of an echoed RZX gate # have opposite signs. for idx in range(1, len(rzx_angles), 2): self.assertAlmostEqual(rzx_angles[idx - 1], -rzx_angles[idx])
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 test_rzx_number_native_weyl_decomposition(self): """Check the number of RZX gates for a hardware-native cx""" qr = QuantumRegister(2, "qr") circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) unitary_circuit = qi.Operator(circuit).data after = EchoRZXWeylDecomposition(self.inst_map)(circuit) unitary_after = qi.Operator(after).data self.assertTrue(np.allclose(unitary_circuit, unitary_after)) # check whether the after circuit has the correct number of rzx gates. self.assertRZXgates(unitary_circuit, after)
def test_save_expval_var_stabilizer_pauli(self, pauli): """Test Pauli expval_var for stabilizer circuit""" SUPPORTED_METHODS = [ 'automatic', 'statevector', 'statevector_gpu', 'statevector_thrust', 'density_matrix', 'density_matrix_gpu', 'density_matrix_thrust', 'matrix_product_state', 'stabilizer' ] SEED = 5832 # Stabilizer test circuit state_circ = qi.random_clifford(2, seed=SEED).to_circuit() oper = qi.Operator(qi.Pauli(pauli)) state = qi.Statevector(state_circ) expval = state.expectation_value(oper).real variance = state.expectation_value(oper**2).real - expval**2 target = [expval, variance] # Snapshot circuit opts = self.BACKEND_OPTS.copy() method = opts.get('method', 'automatic') circ = transpile(state_circ, basis_gates=[ 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'cx', 'cz', 'swap' ]) circ.save_expectation_value_variance(oper, [0, 1], label='expval') qobj = assemble(circ) result = self.SIMULATOR.run(qobj, **opts).result() if method not in SUPPORTED_METHODS: self.assertFalse(result.success) else: self.assertTrue(result.success) value = result.data(0)['expval'] self.assertTrue(allclose(value, target))
def test_save_expval_nonstabilizer_pauli(self, pauli): """Test Pauli expval for non-stabilizer circuit""" SUPPORTED_METHODS = [ 'automatic', 'statevector', 'statevector_gpu', 'statevector_thrust', 'density_matrix', 'density_matrix_gpu', 'density_matrix_thrust', 'matrix_product_state' ] SEED = 7382 # Stabilizer test circuit state_circ = QuantumVolume(2, 1, seed=SEED) oper = qi.Operator(qi.Pauli(pauli)) state = qi.Statevector(state_circ) target = state.expectation_value(oper).real # Snapshot circuit opts = self.BACKEND_OPTS.copy() method = opts.get('method', 'automatic') circ = transpile(state_circ, basis_gates=['u1', 'u2', 'u3', 'cx', 'swap']) circ.save_expectation_value(oper, [0, 1], label='expval') qobj = assemble(circ) result = self.SIMULATOR.run(qobj, **opts).result() if method not in SUPPORTED_METHODS: self.assertFalse(result.success) else: self.assertTrue(result.success) value = result.data(0)['expval'] self.assertAlmostEqual(value, target)
def _test_save_expval(self, circuit, oper, qubits, variance, **options): """Test Pauli expval for stabilizer circuit""" backend = self.backend(**options) label = 'expval' # Format operator and target value circ = circuit.copy() oper = qi.Operator(oper) state = qi.DensityMatrix(circ) expval = state.expectation_value(oper, qubits).real if variance: var = state.expectation_value(oper**2, qubits).real - expval**2 target = [expval, var] circ.save_expectation_value_variance(oper, qubits, label=label) else: target = expval circ.save_expectation_value(oper, qubits, label=label) 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 = simdata[label] if variance: self.assertTrue(allclose(value, target)) else: self.assertAlmostEqual(value, target)
def assert_circuit_equivalence(self, qc, qcd): """ Raise exception if two circuits not equivalent """ I = qc.compose(qcd.inverse()) op = qi.Operator(I) U = op.data / np.sqrt(complex(np.linalg.det(op.data))) U *= U[0, 0] np.testing.assert_almost_equal(U, np.eye(2**qc.num_qubits))
def test_pauli_error_2q_gate_from_string_1qonly(self): """Test two-qubit pauli error as gate qobj from string label""" paulis = ['XI', 'YI', 'ZI'] probs = [0.5, 0.3, 0.2] with self.assertWarns(DeprecationWarning): actual = pauli_error(zip(paulis, probs), standard_gates=True) target_circs = [[{"name": "id", "qubits": [0]}, {"name": "x", "qubits": [1]}], [{"name": "id", "qubits": [0]}, {"name": "y", "qubits": [1]}], [{"name": "id", "qubits": [0]}, {"name": "z", "qubits": [1]}]] with self.assertWarns(DeprecationWarning): expected = QuantumError(zip(target_circs, probs), standard_gates=True) for i in range(actual.size): circ, prob = actual.error_term(i) expected_circ, expected_prob = expected.error_term(i) self.assertTrue(qi.Operator(circ).equiv(qi.Operator(expected_circ))) self.assertAlmostEqual(prob, expected_prob)
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_save_expval_var_stabilizer_pauli(self, method, device, pauli): """Test Pauli expval_var for stabilizer circuit""" SEED = 5832 circ = qi.random_clifford(2, seed=SEED).to_circuit() oper = qi.Operator(qi.Pauli(pauli)) qubits = [0, 1] self._test_save_expval(circ, oper, qubits, True, method=method, device=device)
def test_save_expval_var_nonstabilizer_pauli(self, method, device, pauli): """Test Pauli expval_var for non-stabilizer circuit""" SEED = 7382 circ = QuantumVolume(2, 1, seed=SEED) oper = qi.Operator(qi.Pauli(pauli)) qubits = [0, 1] self._test_save_expval(circ, oper, qubits, True, method=method, device=device)
def _target_quantum_channel( cls, circuit: QuantumCircuit, measurement_qubits: Optional[Sequence[int]] = None, preparation_qubits: Optional[Sequence[int]] = None, ): """Return the process tomography target""" # Check if circuit contains measure instructions # If so we cannot return target state circuit_ops = circuit.count_ops() if "measure" in circuit_ops: return None perm_circ = cls._permute_circuit(circuit, measurement_qubits=measurement_qubits, preparation_qubits=preparation_qubits) try: if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops: channel = qi.Choi(perm_circ) else: channel = qi.Operator(perm_circ) except QiskitError: # Circuit couldn't be simulated return None total_qubits = circuit.num_qubits if measurement_qubits: num_meas = len(measurement_qubits) else: num_meas = total_qubits if preparation_qubits: num_prep = len(preparation_qubits) else: num_prep = total_qubits if num_prep == total_qubits and num_meas == total_qubits: return channel # Trace out non-measurement subsystems tr_qargs = [] if preparation_qubits: tr_qargs += list(range(num_prep, total_qubits)) if measurement_qubits: tr_qargs += list(range(total_qubits + num_meas, 2 * total_qubits)) chan_state = qi.Statevector(np.ravel(channel, order="F")) chan_state = qi.partial_trace(chan_state, tr_qargs) / 2**(total_qubits - num_meas) channel = qi.Choi(chan_state.data, input_dims=[2] * num_prep, output_dims=[2] * num_meas) return channel
def run(self, dag: DAGCircuit): """Run the EchoRZXWeylDecomposition pass on `dag`. Rewrites two-qubit gates in an arbitrary circuit in terms of echoed cross-resonance gates by computing the Weyl decomposition of the corresponding unitary. Modifies the input dag. Args: dag (DAGCircuit): DAG to rewrite. Returns: DAGCircuit: The modified dag. Raises: TranspilerError: If the circuit cannot be rewritten. """ if len(dag.qregs) > 1: raise TranspilerError( "EchoRZXWeylDecomposition expects a single qreg input DAG," f"but input DAG had qregs: {dag.qregs}.") trivial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) decomposer = TwoQubitControlledUDecomposer(RZXGate) for node in dag.two_qubit_ops(): unitary = qi.Operator(node.op).data dag_weyl = circuit_to_dag(decomposer(unitary)) dag.substitute_node_with_dag(node, dag_weyl) for node in dag.two_qubit_ops(): if node.name == "rzx": control = node.qargs[0] target = node.qargs[1] physical_q0 = trivial_layout[control] physical_q1 = trivial_layout[target] is_native = self._is_native((physical_q0, physical_q1)) theta = node.op.params[0] if is_native: dag.substitute_node_with_dag(node, self._echo_rzx_dag(theta)) else: dag.substitute_node_with_dag( node, self._reverse_echo_rzx_dag(theta)) return dag
def test_save_unitary(self, method, device): """Test save unitary instruction""" backend = self.backend(method=method, device=device) # Test circuit SEED = 5426 circ = QuantumVolume(3, seed=SEED) # Target unitary target = qi.Operator(circ) # Add save to circuit label = 'state' circ.save_unitary(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.Operator(simdata[label]) self.assertEqual(value, target)
def test_save_expval_stabilizer_pauli_cache_blocking( self, method, device, pauli): """Test Pauli expval for stabilizer circuit""" SEED = 5832 circ = qi.random_clifford(2, seed=SEED).to_circuit() oper = qi.Operator(qi.Pauli(pauli)) qubits = [0, 1] self._test_save_expval(circ, oper, qubits, False, method=method, device=device, blocking_qubits=2, max_parallel_threads=1)
def test_unitary_snap(self): """Test Unitary matrix snaps on a random circuit""" backend = UnitarySimulator() target = qi.random_unitary(2 ** 4, seed=111) circ = QuantumCircuit(4) circ.append(target, [0, 1, 2, 3]) circ.append(Snapshot("final", "unitary", 4), [0, 1, 2, 3]) qobj = assemble(circ, backend=backend, shots=1) job = backend.run(qobj) result = job.result() self.assertSuccess(result) snaps = result.data(0)['snapshots']['unitary']['final'] for arr in snaps: self.assertTrue(isinstance(arr, np.ndarray)) self.assertEqual(qi.Operator(arr), target)
def test_full_exp_meas_prep_qubits(self, qubits): """Test subset state tomography generation""" # Subsystem unitaries seed = 1111 nq = 3 ops = [qi.random_unitary(2, seed=seed + i) for i in range(nq)] # Target state target_circ = QuantumCircuit(len(qubits)) for i, qubit in enumerate(qubits): target_circ.append(ops[qubit], [i]) target = qi.Operator(target_circ) # Preparation circuit circ = QuantumCircuit(nq) for i, op in enumerate(ops): circ.append(op, [i]) # Run backend = AerSimulator(seed_simulator=9000) exp = ProcessTomography(circ, measurement_qubits=qubits, preparation_qubits=qubits) expdata = exp.run(backend) self.assertExperimentDone(expdata) results = expdata.analysis_results() # Check result f_threshold = 0.95 # Check state is density matrix state = filter_results(results, "state").value self.assertTrue(isinstance(state, qi.Choi), msg="fitted state is not a Choi matrix") # Check fit state fidelity fid = filter_results(results, "process_fidelity").value self.assertGreater(fid, f_threshold, msg="fit fidelity is low") # Manually check fidelity target_fid = qi.process_fidelity(state, target, require_tp=False, require_cp=False) self.assertAlmostEqual(fid, target_fid, places=6, msg="result fidelity is incorrect")
def generate_two_qubit_N_operator(theta): ''' somehow this is diff from the commented out one above lol ohwell this is from Abol's paper ''' qc = QuantumCircuit(2, name = "N({theta})".format(theta = theta)) qc.rz(np.pi/2,1) qc.cx(1,0) qc.rz(2*theta - np.pi/2, 0) qc.ry(np.pi/2 - 2*theta, 1) qc.cx(0,1) qc.ry(2*theta - np.pi/2, 1) qc.cx(1,0) qc.rz(-np.pi/2,0) return qi.Operator(qc)
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 costvsthetas_disc(vth): th1 = np.round(vth[0]) / 32 * pi th2 = np.round(vth[1]) / 32 * pi th3 = np.round(vth[2]) / 32 * pi th4 = np.round(vth[3]) / 32 * pi qc = QuantumCircuit(4) qc.rx(th1, 0) qc.rx(th2, 1) qc.rx(th3, 2) qc.rx(th4, 3) mtrx = qi.Operator(qc).data #mtrx = fourgates(th1, th2, th3, th4) return cost(mtrx - uu)
def test_set_unitary(self, method, device, num_qubits): """Test SetUnitary instruction""" backend = self.backend(method=method, device=device) seed = 100 label = 'state' target = qi.random_unitary(2**num_qubits, seed=seed) circ = QuantumCircuit(num_qubits) circ.set_unitary(target) circ.save_unitary(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.Operator(simdata[label]) self.assertEqual(value, target)
def test_exp_measurement_preparation_qubits(self, qubits): """Test subset measurement process tomography generation""" # Subsystem unitaries seed = 1111 nq = 3 ops = [qi.random_unitary(2, seed=seed + i) for i in range(nq)] # Preparation circuit circ = QuantumCircuit(nq) for i, op in enumerate(ops): circ.append(op, [i]) num_meas = len(qubits) exp = ProcessTomography(circ, measurement_qubits=qubits, preparation_qubits=qubits) tomo_circuits = exp.circuits() # Check correct number of circuits are generated size = 3**num_meas * 4**num_meas self.assertEqual(len(tomo_circuits), size) # Check circuit metadata is correct for circ in tomo_circuits: meta = circ.metadata clbits = meta.get("clbits") self.assertEqual(clbits, list(range(num_meas)), msg="metadata clbits is incorrect") # Check experiment target metadata is correct exp_meta = exp._metadata() target_state = exp_meta.get("target") target_circ = QuantumCircuit(num_meas) for i, qubit in enumerate(qubits): target_circ.append(ops[qubit], [i]) fid = qi.process_fidelity(target_state, qi.Operator(target_circ)) self.assertGreater(fid, 0.99, msg="target_state is incorrect")
def circ2matrix(qc=None): #pl.figure() #figsize=(20,9)) pl.clf() if not qc: qc = QuantumCircuit(4) else: uc = qi.Operator(qc).data pl.subplot(121) plu(uc) pl.subplot(122) plu(uc / compru(uc[0:2, 0:2]), ampl=False) be = aer.get_backend('unitary_simulator') ucompr = compru(u22) gatestr = input('Next gate: ') while gatestr != 'q': if gatestr == 'r': qc = QuantumCircuit(4) elif gatestr[0:3] != 'qc.': try: exec(gatestr) except: print('ignoring previous command') else: #exec('qc.'+gatestr.strip()) try: exec(gatestr) goodgate = True except: goodgate = False print('ignoring this gate') if goodgate: uc = qi.Operator(qc).data uc22 = uc[0:2, 0:2] u4by4 = np.concatenate((uc22, uc22), axis=0) u4by4 = np.concatenate((u4by4, u4by4), axis=1) xuc22 = X @ uc22 x4by4 = np.concatenate((xuc22, xuc22), axis=0) x4by4 = np.concatenate((x4by4, x4by4), axis=1) u8by8 = np.concatenate((u4by4, x4by4), axis=1) u8by8 = np.concatenate( (u8by8, np.concatenate((x4by4, u4by4), axis=1)), axis=0) compr = np.concatenate((np.concatenate( (u8by8, u8by8), axis=1), np.concatenate((u8by8, u8by8), axis=1)), axis=0) """ pl.subplot(221) plu(uu) pl.subplot(222) plu(uu/ucompr) """ pl.clf() pl.subplot(121) plu(uc) #pl.show(block=False) pl.subplot(122) plu(uc / compr, ampl=False) #pl.show(block=False) gatestr = input('Next gate: ')
def get_unitary(circuit: QuantumCircuit) -> np.ndarray: V = qi.Operator(circuit).data return V
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
noise_transform_to_left_channel(L) for i in range(len(L)): if L[i].pulse_type == 'noise': pulse_noise.append(L[i]) m = np.identity(2) for i in reversed(range(len(pulse_noise))): m = pulse_to_unitary( pulse_noise[i], delta / 2) @ m # delta/2: 1/2 here because of Clifford decomposition noise_unitary.append(m) depol_str = [] for i in range(len(noise_unitary)): ch = quantum_info.Operator(noise_unitary[i]) F_ave = quantum_info.average_gate_fidelity(ch) p = (d * F_ave - 1) / (d - 1) depol_str.append(p) avg_depol_str.append(np.mean(depol_str)) depha_m = np.cos(delta) * I_1q - 1j * np.sin(delta) * Z_1q depha_ch = quantum_info.Operator(depha_m) F_depha = quantum_info.average_gate_fidelity(depha_ch) p_depha = (d * F_depha - 1) / (d - 1) depha_str.append(p_depha) plot1 = plt.figure(1) plt.plot(delta_list, depha_str, 'ro', markersize=2, label='channel noise') plt.plot(delta_list, avg_depol_str,