def test_to_quantumchannel_kraus(self): """Test to_quantumchannel for Kraus inputs.""" a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) b_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) b_1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) target = SuperOp(Kraus([a_0, a_1])).tensor(SuperOp(Kraus([b_0, b_1]))) error = QuantumError([a_0, a_1]).tensor(QuantumError([b_0, b_1])) self.assertEqual(target, error.to_quantumchannel())
def test_pauli_conversion_standard_gates(self): """Test conversion of Pauli channel kraus to gates""" kraus, error = self.depol_error(1, standard_gates=True) for j in range(4): instr, _ = error.error_term(j) self.assertEqual(len(instr), 1) self.assertIn(instr[0][0].name, ['x', 'y', 'z', 'id']) self.assertEqual(self.qubits_list(instr, instr[0][1]), [0]) target = SuperOp(kraus) self.assertEqual(target, SuperOp(error))
def test_expand_unitary_and_kraus(self): """Test expand of a unitary and kraus error.""" kraus, error_kraus = self.kraus_error(0.4) kraus_unitaries, error_unitaries = self.depol_error(0.1) error = error_unitaries.expand(error_kraus) target = SuperOp(kraus_unitaries).expand(kraus) circ, prob = error.error_term(0) self.assertEqual(self.qubits_list(circ, circ.qubits), [0, 1]) self.assertEqual(target, SuperOp(error))
def test_compose_unitary_and_kraus(self): """Test compose of a unitary and kraus error.""" kraus, error_kraus = self.kraus_error(0.4) kraus_unitaries, error_unitaries = self.depol_error(0.1) error = error_unitaries.compose(error_kraus) target = SuperOp(kraus_unitaries).compose(kraus) circ, prob = error.error_term(0) self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(target, SuperOp(error))
def test_pauli_conversion_unitary(self): """Test conversion of Pauli channel kraus to unitary qobj""" error = QuantumError(self.depol_error(1), standard_gates=False) for j in range(4): instr, _ = error.error_term(j) self.assertEqual(len(instr), 1) self.assertIn(instr[0]['name'], ['unitary', 'id']) self.assertEqual(instr[0]['qubits'], [0]) target = SuperOp(Kraus(self.depol_error(1))) self.assertEqual(target, SuperOp(error))
def test_dot_kraus_and_unitary(self): """Test dot of a kraus and unitary error.""" kraus, error_kraus = self.kraus_error(0.4) kraus_unitaries, error_unitaries = self.depol_error(0.1) error = error_kraus.dot(error_unitaries) target = SuperOp(kraus).dot(kraus_unitaries) circ, prob = error.error_term(0) self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(target, SuperOp(error))
def test_dot_unitary_and_kraus(self): """Test dot of a unitary and kraus error.""" kraus = self.kraus_error(0.4) unitaries = self.depol_error(0.1) error = QuantumError(unitaries).dot(QuantumError(kraus)) target = SuperOp(Kraus(unitaries)).dot(Kraus(kraus)) circ, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(circ[0]['name'], 'kraus') self.assertEqual(circ[0]['qubits'], [0]) self.assertEqual(target, SuperOp(error))
def test_dot_both_kraus(self): """Test dot of two kraus errors""" kraus0 = self.kraus_error(0.3) kraus1 = self.kraus_error(0.5) error = QuantumError(kraus0).dot(QuantumError(kraus1)) target = SuperOp(Kraus(kraus0)).dot(Kraus(kraus1)) kraus, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0]) self.assertEqual(target, SuperOp(error), msg="Incorrect dot kraus")
def test_compose_kraus_and_unitary(self): """Test compose of a kraus and unitary error.""" kraus = self.kraus_error(0.4) unitaries = self.depol_error(0.1) error = QuantumError(kraus).compose(QuantumError(unitaries)) target = SuperOp(Kraus(kraus)).compose(Kraus(unitaries)) circ, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(circ[0]['name'], 'kraus') self.assertEqual(circ[0]['qubits'], [0]) self.assertEqual(target, SuperOp(error))
def test_expand_both_kraus(self): """Test expand of two kraus errors""" kraus0 = self.kraus_error(0.3) kraus1 = self.kraus_error(0.5) error = QuantumError(kraus0).expand(QuantumError(kraus1)) target = SuperOp(Kraus(kraus0)).expand(Kraus(kraus1)) circ, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(circ[0]['name'], 'kraus') self.assertEqual(circ[0]['qubits'], [0, 1]) self.assertEqual(target, SuperOp(error))
def test_tensor_both_kraus(self): """Test tensor of two kraus errors""" kraus0, error_kraus0 = self.kraus_error(0.3) kraus1, error_kraus1 = self.kraus_error(0.5) error = error_kraus0.tensor(error_kraus1) target = SuperOp(kraus0).tensor(kraus1) circ, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(circ[0][0].name, 'kraus') self.assertEqual(self.qubits_list(circ, circ.qubits), [0, 1]) self.assertEqual(target, SuperOp(error), msg="Incorrect tensor kraus")
def test_dot_unitary_and_kraus(self): """Test dot of a unitary and kraus error.""" kraus, error_kraus = self.kraus_error(0.4) kraus_unitaries, error_unitaries = self.depol_error(0.1) error = error_unitaries.dot(error_kraus) target = SuperOp(kraus_unitaries).dot(kraus) circ, prob = error.error_term(0) # self.assertEqual(prob, 1) self.assertEqual(circ[0][0].name, 'kraus') self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(target, SuperOp(error))
def test_dot_both_kraus(self): """Test dot of two kraus errors""" kraus0, error0 = self.kraus_error(0.3) kraus1, error1 = self.kraus_error(0.5) error = error0.dot(error1) target = SuperOp(kraus0).dot(kraus1) kraus, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(kraus[0][0].name, 'kraus') self.assertEqual(self.qubits_list(kraus, kraus[0][1]), [0]) self.assertEqual(target, SuperOp(error), msg="Incorrect dot kraus")
def test_compose_kraus_and_unitary(self): """Test compose of a kraus and unitary error.""" kraus, error_kraus = self.kraus_error(0.4) kraus_unitaries, error_unitaries = self.depol_error(0.1) error = error_kraus.compose(error_unitaries) target = SuperOp(kraus).compose(kraus_unitaries) circ, prob = error.error_term(0) # self.assertEqual(prob, 1) self.assertEqual(circ[0][0].name, 'kraus') self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(target, SuperOp(error))
def test_to_quantumchannel_kraus(self): """Test to_quantumchannel for Kraus inputs.""" a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) b_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) b_1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) target = SuperOp(Kraus([a_0, a_1])).tensor(SuperOp(Kraus([b_0, b_1]))) with self.assertWarns( DeprecationWarning, msg=r"Constructing QuantumError .* Kraus channel .* qiskit-aer 0\.10\.0 .*", ): error = QuantumError([a_0, a_1]).tensor(QuantumError([b_0, b_1])) self.assertEqual(target, error.to_quantumchannel())
def test_expand_both_kraus(self): """Test expand of two kraus errors""" kraus0, error0 = self.kraus_error(0.3) kraus1, error1 = self.kraus_error(0.5) error = error0.expand(error1) target = SuperOp(kraus0).expand(kraus1) circ, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(circ[0][0].name, 'kraus') self.assertEqual(circ[1][0].name, 'kraus') self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(self.qubits_list(circ, circ[1][1]), [1]) self.assertEqual(target, SuperOp(error))
def test_dot_both_unitary_standard_gates(self): """Test dot of two unitary standard gate errors""" unitaries0 = self.mixed_unitary_error([0.9, 0.1], ['z', 's']) unitaries1 = self.mixed_unitary_error([0.6, 0.4], ['x', 'y']) error0 = QuantumError(unitaries0, standard_gates=True) error1 = QuantumError(unitaries1, standard_gates=True) error = error0.dot(error1) target = SuperOp(Kraus(unitaries0)).dot(Kraus(unitaries1)) for j in range(4): circ, _ = error.error_term(j) self.assertIn(circ[0]['name'], ['s', 'x', 'y', 'z']) self.assertEqual(circ[0]['qubits'], [0]) self.assertEqual(SuperOp(error), target)
def test_compose_both_unitary_instruction(self): """Test compose of two unitary instruction errors.""" unitaries0 = self.mixed_unitary_error([0.9, 0.1], ['z', 's']) unitaries1 = self.mixed_unitary_error([0.6, 0.4], ['x', 'y']) error0 = QuantumError(unitaries0, standard_gates=False) error1 = QuantumError(unitaries1, standard_gates=False) error = error0.compose(error1) target = SuperOp(Kraus(unitaries0)).compose(Kraus(unitaries1)) for j in range(4): circ, _ = error.error_term(j) self.assertEqual(circ[0]['name'], 'unitary') self.assertEqual(circ[0]['qubits'], [0]) self.assertEqual(SuperOp(error), target)
def _compose_instr(instr0, instr1): """Helper function for compose a kraus with another instruction.""" # If one of the instructions is an identity we only need # to return the other instruction if instr0['name'] == 'id': return instr1 if instr1['name'] == 'id': return instr0 # Check qubits match qubits0 = instr0['qubits'] qubits1 = instr1['qubits'] if qubits0 != qubits1: raise NoiseError("Unitary instructions are on different qubits") # Convert to ops op0 = QuantumError._instr2op(instr0) op1 = QuantumError._instr2op(instr1) # Check if at least one of the instructions is a channel # and if so convert to Kraus representation. if isinstance(op0, (SuperOp, Kraus)) or isinstance(op1, (SuperOp, Kraus)): name = 'kraus' params = Kraus(SuperOp(op0).compose(op1)).data else: name = 'unitary' params = op0.compose(op1).data return {'name': name, 'qubits': qubits0, 'params': params}
def test_dot_both_unitary_standard_gates(self): """Test dot of two unitary standard gate errors""" kraus0, error0 = self.mixed_unitary_error( [0.9, 0.1], ['z', 's'], standard_gates=True, ) kraus1, error1 = self.mixed_unitary_error( [0.6, 0.4], ['x', 'y'], standard_gates=True, ) error = error0.dot(error1) target = SuperOp(kraus0).dot(kraus1) for j in range(4): circ, _ = error.error_term(j) self.assertIn(circ[0][0].name, ['s', 'x', 'y', 'z']) self.assertEqual(self.qubits_list(circ, circ[0][1]), [0]) self.assertEqual(SuperOp(error), target)
def test_tensor_both_unitary_standard_gates(self): """Test tensor of two unitary standard gate errors""" unitaries0 = self.mixed_unitary_error([0.9, 0.1], ['z', 's']) unitaries1 = self.mixed_unitary_error([0.6, 0.4], ['x', 'y']) error0 = QuantumError(unitaries0, standard_gates=True) error1 = QuantumError(unitaries1, standard_gates=True) error = error0.tensor(error1) target = SuperOp(Kraus(unitaries0)).tensor(Kraus(unitaries1)) for j in range(4): circ, _ = error.error_term(j) self.assertEqual(len(circ), 2) for instr in circ: self.assertIn(instr['name'], ['s', 'x', 'y', 'z']) self.assertIn(instr['qubits'], [[0], [1]]) self.assertEqual(SuperOp(error), target)
def test_to_quantum_channel(self): """Test conversion into quantum channel.""" meas_kraus = Kraus([np.diag([1, 0]), np.diag([0, 1])]) actual = QuantumError(meas_kraus).to_quantumchannel() expected = SuperOp(np.diag([1, 0, 0, 1])) self.assertEqual(actual, expected)
def test_expand_both_unitary_standard_gates(self): """Test expand of two unitary standard gate errors""" kraus0, error0 = self.mixed_unitary_error( [0.9, 0.1], ['z', 's'], standard_gates=True, ) kraus1, error1 = self.mixed_unitary_error( [0.6, 0.4], ['x', 'y'], standard_gates=True, ) error = error0.expand(error1) target = SuperOp(kraus0).expand(kraus1) for j in range(4): circ, _ = error.error_term(j) self.assertEqual(len(circ), 2) for instr, qargs, _ in circ: self.assertIn(instr.name, ['s', 'x', 'y', 'z']) self.assertIn(self.qubits_list(circ, qargs), [[0], [1]]) self.assertEqual(SuperOp(error), target)
def to_quantumchannel(self): """Convert the QuantumError to a SuperOp quantum channel.""" # Initialize as an empty superoperator of the correct size dim = 2**self.number_of_qubits channel = SuperOp(np.zeros([dim * dim, dim * dim])) for circuit, prob in zip(self._noise_circuits, self._noise_probabilities): component = prob * circuit2superop(circuit, self.number_of_qubits) channel = channel + component return channel
def test_kraus(self): """ Test Kraus. See https://github.com/Qiskit/qiskit-terra/pull/2238#issuecomment-487630014""" expected = '\n'.join( [" ┌───────┐", "q_0: |0>┤ Kraus ├", " └───────┘"]) error = SuperOp(0.75 * numpy.eye(4) + 0.25 * numpy.diag([1, -1, -1, 1])) qr = QuantumRegister(1, name='q') qc = QuantumCircuit(qr) qc.append(error, [qr[0]]) self.assertEqual(str(_text_circuit_drawer(qc)), expected)
def _combine_kraus(noise_ops, num_qubits): """Combine any noise circuits containing only Kraus instructions.""" kraus_instr = [] kraus_probs = [] new_circuits = [] new_probs = [] # Partion circuits into Kraus and non-Kraus for circuit, prob in noise_ops: if len(circuit) == 1 and circuit[0]['name'] == 'kraus': kraus_instr.append(circuit[0]) kraus_probs.append(prob) else: new_circuits.append(circuit) new_probs.append(prob) # Combine matching Kraus instructions via Choi rep if len(kraus_probs) == 1: new_circuits.append([kraus_instr[0]]) new_probs.append(kraus_probs[0]) elif len(kraus_probs) > 1: dim = 2**num_qubits iden = SuperOp(np.eye(dim**2)) choi_sum = Choi(np.zeros((dim**2, dim**2))) for prob, instr in zip(kraus_probs, kraus_instr): choi_sum = choi_sum + prob * iden.compose( Kraus(instr['params']), instr['qubits']) # Renormalize the Choi operator to find probability # of Kraus error chan_prob = abs(np.trace(choi_sum.data) / dim) chan_instr = { "name": "kraus", "qubits": list(range(num_qubits)), "params": Kraus(choi_sum / chan_prob).data } new_circuits.append([chan_instr]) new_probs.append(chan_prob) return list(zip(new_circuits, new_probs))
def _compose_instr(instr0, instr1, num_qubits): """Helper function for compose a kraus with another instruction.""" # If one of the instructions is an identity we only need # to return the other instruction if instr0['name'] == 'id': return instr1 if instr1['name'] == 'id': return instr0 # Convert to ops op0 = QuantumError._instr2op(instr0) op1 = QuantumError._instr2op(instr1) # Check if at least one of the instructions is a channel # and if so convert both to SuperOp representation if isinstance(op0, (SuperOp, Kraus)) or isinstance(op1, (SuperOp, Kraus)): name = 'kraus' op0 = SuperOp(op0) op1 = SuperOp(op1) else: name = 'unitary' # Check qubits for compositions qubits0 = instr0['qubits'] qubits1 = instr1['qubits'] if qubits0 == qubits1: composed = op0.compose(op1) qubits = qubits0 else: # If qubits don't match we compose with total number of qubits # for the error if name == 'kraus': composed = SuperOp(np.eye(4 ** num_qubits)) else: composed = Operator(np.eye(2 ** num_qubits)) composed.compose(op0, qargs=qubits0).compose(op1, qargs=qubits1) qubits = list(range(num_qubits)) # Get instruction params if name == 'kraus': params = Kraus(composed).data else: params = [composed.data] return {'name': name, 'qubits': qubits, 'params': params}
def test_to_quantumchannel_circuit(self): """Test to_quantumchannel for circuit inputs.""" noise_ops = [([{ 'name': 'reset', 'qubits': [0] }], 0.2), ([{ 'name': 'reset', 'qubits': [1] }], 0.3), ([{ 'name': 'id', 'qubits': [0] }], 0.5)] error = QuantumError(noise_ops) reset = SuperOp( np.array([[1, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])) iden = SuperOp(np.eye(4)) target = 0.2 * iden.tensor(reset) + 0.3 * reset.tensor( iden) + 0.5 * iden.tensor(iden) self.assertEqual(target, error.to_quantumchannel())
def _tensor_instr(instr0, instr1): """Tensor of two operator qobj instructions.""" # If one of the instructions is an identity we only need # to return the other instruction if instr0['name'] == 'id': return instr1 if instr1['name'] == 'id': return instr0 # Combine qubits qubits = instr0['qubits'] + instr1['qubits'] # Convert to ops op0 = QuantumError._instr2op(instr0) op1 = QuantumError._instr2op(instr1) # Check if at least one of the instructions is a channel # and if so convert to Kraus representation. if isinstance(op0, SuperOp) or isinstance(op1, SuperOp): name = 'kraus' params = Kraus(SuperOp(op0).expand(op1)).data else: name = 'unitary' params = [op0.expand(op1).data] return {'name': name, 'qubits': qubits, 'params': params}
def test_to_quantumchannel_circuit(self): """Test to_quantumchannel for circuit inputs.""" noise_ops = [ ([{'name': 'reset', 'qubits': [0]}], 0.2), ([{'name': 'reset', 'qubits': [1]}], 0.3), ([{'name': 'id', 'qubits': [0]}], 0.5), ] with self.assertWarns( DeprecationWarning, msg=r"Constructing QuantumError .* list of dict .* qiskit-aer 0\.10\.0 .*", ): error = QuantumError(noise_ops) reset = SuperOp( np.array([[1, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ) iden = SuperOp(np.eye(4)) target = ( 0.2 * iden.tensor(reset) + 0.3 * reset.tensor(iden) + 0.5 * iden.tensor(iden) ) self.assertEqual(target, error.to_quantumchannel())