def test_reshape(self): """Test Operator _reshape method.""" op = Operator(self.rand_matrix(8, 8)) self.assertEqual(op.output_dims(), (2, 2, 2)) self.assertEqual(op.input_dims(), (2, 2, 2)) op._reshape(input_dims=[8], output_dims=[8]) self.assertEqual(op.output_dims(), (8, )) self.assertEqual(op.input_dims(), (8, )) op._reshape(input_dims=[4, 2], output_dims=[2, 4]) self.assertEqual(op.output_dims(), (2, 4)) self.assertEqual(op.input_dims(), (4, 2))
def test_chi_tensor_random(self): """Test tensor of Chi matrices is correct.""" mats = [self.rand_matrix(2, 2) for _ in range(4)] chans = [Chi(Operator(mat)) for mat in mats] self._compare_tensor_to_operator(chans, mats)
def test_kraus_compose_random(self): """Test compose of Kraus matrices is correct.""" mats = [self.rand_matrix(4, 4) for _ in range(4)] chans = [Kraus(Operator(mat)) for mat in mats] self._compare_compose_to_operator(chans, mats)
def test_negate(self): """Test negate method""" mat = self.rand_matrix(4, 4) op = Operator(mat) self.assertEqual(-op, Operator(-1 * mat))
def test_evolve_subsystem(self): """Test subsystem evolve method for operators.""" # Test evolving single-qubit of 3-qubit system for _ in range(5): rho = self.rand_rho(8) state = DensityMatrix(rho) op0 = random_unitary(2) op1 = random_unitary(2) op2 = random_unitary(2) # Test evolve on 1-qubit op = op0 op_full = Operator(np.eye(4)).tensor(op) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[0]), target) # Evolve on qubit 1 op_full = Operator(np.eye(2)).tensor(op).tensor(np.eye(2)) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[1]), target) # Evolve on qubit 2 op_full = op.tensor(np.eye(4)) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[2]), target) # Test evolve on 2-qubits op = op1.tensor(op0) # Evolve on qubits [0, 2] op_full = op1.tensor(np.eye(2)).tensor(op0) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[0, 2]), target) # Evolve on qubits [2, 0] op_full = op0.tensor(np.eye(2)).tensor(op1) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[2, 0]), target) # Test evolve on 3-qubits op = op2.tensor(op1).tensor(op0) # Evolve on qubits [0, 1, 2] op_full = op target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[0, 1, 2]), target) # Evolve on qubits [2, 1, 0] op_full = op0.tensor(op1).tensor(op2) target = DensityMatrix( np.dot(op_full.data, rho).dot(op_full.adjoint().data)) self.assertEqual(state.evolve(op, qargs=[2, 1, 0]), target)
def test_compose_except(self): """Test compose different dimension exception""" self.assertRaises(QiskitError, Operator(np.eye(2)).compose, Operator(np.eye(3))) self.assertRaises(QiskitError, Operator(np.eye(2)).compose, 2)
def test_power_except(self): """Test power method raises exceptions if not square.""" op = Operator(self.rand_matrix(2, 3)) # Non-integer power raises error self.assertRaises(QiskitError, op.power, 0.5)
def to_operator(self): """Convert to an Operator object.""" return Operator(self.to_instruction())
def to_operator(self): """Convert to an Operator object.""" return Operator(self.to_matrix(), input_dims=self.input_dims(), output_dims=self.output_dims())
def to_operator(self): """Convert to Operator object.""" # Place import here to avoid cyclic import from circuit visualization from qiskit.quantum_info.operators.operator import Operator return Operator(self.to_matrix())
def process_fidelity(channel, target=None, require_cp=True, require_tp=False): r"""Return the process fidelity of a noisy quantum channel. This process fidelity :math:`F_{\text{pro}}` is given by .. math:: F_{\text{pro}}(\mathcal{E}, U) = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2} where :math:`S_{\mathcal{E}}, S_{U}` are the :class:`~qiskit.quantum_info.SuperOp` matrices for the input quantum *channel* :math:`\cal{E}` and *target* unitary :math:`U` respectively, and :math:`d` is the dimension of the *channel*. Args: channel (QuantumChannel or Operator): noisy quantum channel. target (Operator or None): target unitary operator. If `None` target is the identity operator [Default: None]. require_cp (bool): require channel to be completely-positive [Default: True]. require_tp (bool): require channel to be trace-preserving [Default: False]. Returns: float: The process fidelity :math:`F_{\text{pro}}`. Raises: QiskitError: if the channel and target do not have the same dimensions, or have different input and output dimensions. QiskitError: if the channel and target or are not completely-positive (with ``require_cp=True``) or not trace-preserving (with ``require_tp=True``). """ # Format inputs if isinstance(channel, (list, np.ndarray, Operator, Pauli, Clifford)): channel = Operator(channel) else: channel = SuperOp(channel) if target is not None: try: target = Operator(target) except QiskitError: raise QiskitError('Target channel is not a unitary channel.') if channel.dim != target.dim: raise QiskitError( 'Input quantum channel and target unitary must have the same ' 'dimensions ({} != {}).'.format(channel.dim, target.dim)) # Validate complete-positivity and trace-preserving if require_cp or require_tp: # Validate target channel if target is not None: is_unitary = target.is_unitary() if require_cp and not is_unitary: raise QiskitError( 'Target unitary channel is not completely-positive') if require_tp and not is_unitary: raise QiskitError( 'Target unitary channel is not trace-preserving') # Validate input channel if isinstance(channel, Operator): is_unitary = channel.is_unitary() # Validate as unitary if require_cp and not is_unitary: raise QiskitError( 'Input quantum channel is not completely-positive') if require_tp and not is_unitary: raise QiskitError( 'Input quantum channel is not trace-preserving') else: # Validate as QuantumChannel if require_cp and not channel.is_cp(): raise QiskitError( 'Input quantum channel is not completely-positive') if require_tp and not channel.is_tp(): raise QiskitError( 'Input quantum channel is not trace-preserving') # Compute process fidelity with identity channel if target is not None: channel = channel.compose(target.adjoint()) input_dim, _ = channel.dim if isinstance(channel, Operator): # |Tr[U]/dim| ** 2 fid = np.abs(np.trace(channel.data) / input_dim)**2 else: # Tr[S] / (dim ** 2) fid = np.trace(SuperOp(channel).data) / (input_dim**2) return float(np.real(fid))
def test_multiply_except(self): """Test multiply method raises exceptions.""" op = Operator(self.rand_matrix(2, 2)) self.assertRaises(QiskitError, op.multiply, 's') self.assertRaises(QiskitError, op.multiply, op)
def test_subtract_except(self): """Test subtract method raises exceptions.""" op1 = Operator(self.rand_matrix(2, 2)) op2 = Operator(self.rand_matrix(3, 3)) self.assertRaises(QiskitError, op1.subtract, op2)
def test_evolve_subsystem(self): """Test subsytem _evolve method.""" # Test evolving single-qubit of 3-qubit system mat = self.rand_matrix(2, 2) op = Operator(mat) psi = self.rand_matrix(1, 8).flatten() rho = self.rand_rho(8) # Evolve on qubit 0 mat0 = np.kron(np.eye(4), mat) psi0_targ = np.dot(mat0, psi) self.assertAllClose(op._evolve(psi, qargs=[0]), psi0_targ) rho0_targ = np.dot(np.dot(mat0, rho), np.conj(mat0.T)) self.assertAllClose(op._evolve(rho, qargs=[0]), rho0_targ) # Evolve on qubit 1 mat1 = np.kron(np.kron(np.eye(2), mat), np.eye(2)) psi1_targ = np.dot(mat1, psi) self.assertAllClose(op._evolve(psi, qargs=[1]), psi1_targ) rho1_targ = np.dot(np.dot(mat1, rho), np.conj(mat1.T)) self.assertAllClose(op._evolve(rho, qargs=[1]), rho1_targ) # Evolve on qubit 2 mat2 = np.kron(mat, np.eye(4)) psi2_targ = np.dot(mat2, psi) self.assertAllClose(op._evolve(psi, qargs=[2]), psi2_targ) rho2_targ = np.dot(np.dot(mat2, rho), np.conj(mat2.T)) self.assertAllClose(op._evolve(rho, qargs=[2]), rho2_targ) # Test 2-qubit evolution mat_a = self.rand_matrix(2, 2) mat_b = self.rand_matrix(2, 2) op = Operator(np.kron(mat_b, mat_a)) psi = self.rand_matrix(1, 8).flatten() rho = self.rand_rho(8) # Evolve on qubits [0, 2] mat02 = np.kron(mat_b, np.kron(np.eye(2), mat_a)) psi02_targ = np.dot(mat02, psi) self.assertAllClose(op._evolve(psi, qargs=[0, 2]), psi02_targ) rho02_targ = np.dot(np.dot(mat02, rho), np.conj(mat02.T)) self.assertAllClose(op._evolve(rho, qargs=[0, 2]), rho02_targ) # Evolve on qubits [2, 0] mat20 = np.kron(mat_a, np.kron(np.eye(2), mat_b)) psi20_targ = np.dot(mat20, psi) self.assertAllClose(op._evolve(psi, qargs=[2, 0]), psi20_targ) rho20_targ = np.dot(np.dot(mat20, rho), np.conj(mat20.T)) self.assertAllClose(op._evolve(rho, qargs=[2, 0]), rho20_targ) # Test evolve on 3-qubits mat_a = self.rand_matrix(2, 2) mat_b = self.rand_matrix(2, 2) mat_c = self.rand_matrix(2, 2) op = Operator(np.kron(mat_c, np.kron(mat_b, mat_a))) psi = self.rand_matrix(1, 8).flatten() rho = self.rand_rho(8) # Evolve on qubits [0, 1, 2] mat012 = np.kron(mat_c, np.kron(mat_b, mat_a)) psi012_targ = np.dot(mat012, psi) self.assertAllClose(op._evolve(psi, qargs=[0, 1, 2]), psi012_targ) rho012_targ = np.dot(np.dot(mat012, rho), np.conj(mat012.T)) self.assertAllClose(op._evolve(rho, qargs=[0, 1, 2]), rho012_targ) # Evolve on qubits [2, 1, 0] mat210 = np.kron(mat_a, np.kron(mat_b, mat_c)) psi210_targ = np.dot(mat210, psi) self.assertAllClose(op._evolve(psi, qargs=[2, 1, 0]), psi210_targ) rho210_targ = np.dot(np.dot(mat210, rho), np.conj(mat210.T)) self.assertAllClose(op._evolve(rho, qargs=[2, 1, 0]), rho210_targ)
def test_reshape_raise(self): """Test Operator reshape method with invalid args.""" op = Operator(self.rand_matrix(3, 3)) self.assertRaises(QiskitError, op.reshape, num_qubits=2)
def process_fidelity(channel, target=None, require_cp=True, require_tp=False, require_cptp=False): r"""Return the process fidelity of a noisy quantum channel. This process fidelity :math:`F_{\text{pro}}` is given by .. math:: F_{\text{pro}}(\mathcal{E}, U) = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2} where :math:`S_{\mathcal{E}}, S_{U}` are the :class:`~qiskit.quantum_info.SuperOp` matrices for the input quantum *channel* :math:`\cal{E}` and *target* unitary :math:`U` respectively, and :math:`d` is the dimension of the *channel*. Args: channel (QuantumChannel): noisy quantum channel. target (Operator or None): target unitary operator. If `None` target is the identity operator [Default: None]. require_cp (bool): require channel to be completely-positive [Default: True]. require_tp (bool): require channel to be trace-preserving [Default: False]. require_cptp (bool): (DEPRECATED) require input channels to be CPTP [Default: False]. Returns: float: The process fidelity :math:`F_{\text{pro}}`. Raises: QiskitError: if the channel and target do not have the same dimensions, or have different input and output dimensions. QiskitError: if the channel and target or are not completely-positive (with ``require_cp=True``) or not trace-preserving (with ``require_tp=True``). """ # Format inputs if isinstance(channel, (list, np.ndarray, Operator, Pauli)): channel = Operator(channel) else: channel = SuperOp(channel) input_dim, output_dim = channel.dim if input_dim != output_dim: raise QiskitError( 'Quantum channel must have equal input and output dimensions.') if target is not None: # Multiple channel by adjoint of target target = Operator(target) if (input_dim, output_dim) != target.dim: raise QiskitError( 'Quantum channel and target must have the same dimensions.') channel = channel @ target.adjoint() # Validate complete-positivity and trace-preserving if require_cptp: # require_cptp kwarg is DEPRECATED # Remove in future qiskit version warnings.warn( "Please use `require_cp=True, require_tp=True` " "instead of `require_cptp=True`.", DeprecationWarning) require_cp = True require_tp = True if isinstance(channel, Operator) and (require_cp or require_tp): is_unitary = channel.is_unitary() # Validate as unitary if require_cp and not is_unitary: raise QiskitError('channel is not completely-positive') if require_tp and not is_unitary: raise QiskitError('channel is not trace-preserving') else: # Validate as QuantumChannel if require_cp and not channel.is_cp(): raise QiskitError('channel is not completely-positive') if require_tp and not channel.is_tp(): raise QiskitError('channel is not trace-preserving') # Compute process fidelity with identity channel if isinstance(channel, Operator): # |Tr[U]/dim| ** 2 fid = np.abs(np.trace(channel.data) / input_dim)**2 else: # Tr[S] / (dim ** 2) fid = np.trace(channel.data) / (input_dim**2) return float(np.real(fid))
def test_to_operator(self): """Test to_operator method.""" op1 = Operator(self.rand_matrix(4, 4)) op2 = op1.to_operator() self.assertEqual(op1, op2)
def to_operator(self): """Convert to a matrix Operator object""" return Operator(self.to_matrix())
def test_compose_front_subsystem(self): """Test subsystem front compose method.""" # 3-qubit operator mat = self.rand_matrix(8, 8) mat_a = self.rand_matrix(2, 2) mat_b = self.rand_matrix(2, 2) mat_c = self.rand_matrix(2, 2) op = Operator(mat) op1 = Operator(mat_a) op2 = Operator(np.kron(mat_b, mat_a)) op3 = Operator(np.kron(mat_c, np.kron(mat_b, mat_a))) # op3 qargs=[0, 1, 2] targ = np.dot(mat, np.kron(mat_c, np.kron(mat_b, mat_a))) self.assertEqual(op.compose(op3, qargs=[0, 1, 2], front=True), Operator(targ)) # op3 qargs=[2, 1, 0] targ = np.dot(mat, np.kron(mat_a, np.kron(mat_b, mat_c))) self.assertEqual(op.compose(op3, qargs=[2, 1, 0], front=True), Operator(targ)) # op2 qargs=[0, 1] targ = np.dot(mat, np.kron(np.eye(2), np.kron(mat_b, mat_a))) self.assertEqual(op.compose(op2, qargs=[0, 1], front=True), Operator(targ)) # op2 qargs=[2, 0] targ = np.dot(mat, np.kron(mat_a, np.kron(np.eye(2), mat_b))) self.assertEqual(op.compose(op2, qargs=[2, 0], front=True), Operator(targ)) # op1 qargs=[0] targ = np.dot(mat, np.kron(np.eye(4), mat_a)) self.assertEqual(op.compose(op1, qargs=[0], front=True), Operator(targ)) # op1 qargs=[1] targ = np.dot(mat, np.kron(np.eye(2), np.kron(mat_a, np.eye(2)))) self.assertEqual(op.compose(op1, qargs=[1], front=True), Operator(targ)) # op1 qargs=[2] targ = np.dot(mat, np.kron(mat_a, np.eye(4))) self.assertEqual(op.compose(op1, qargs=[2], front=True), Operator(targ))
def to_operator(self): """Convert to Operator""" dims = self.dims() return Operator(self.data, input_dims=dims, output_dims=dims)
def test_add_except(self): """Test add method raises exceptions.""" op1 = Operator(self.rand_matrix(2, 2)) op2 = Operator(self.rand_matrix(3, 3)) self.assertRaises(QiskitError, op1._add, op2)
def to_operator(self): """Convert state to a rank-1 projector operator""" mat = np.outer(self.data, np.conj(self.data)) return Operator(mat, input_dims=self.dims(), output_dims=self.dims())
def test_from_circuit_empty_circuit_empty_layout(self): """Test an out of order ghz state with a layout set.""" circuit = QuantumCircuit() circuit._layout = Layout() op = Operator.from_circuit(circuit) self.assertEqual(Operator([1]), op)
def test_init_operator(self): """Test initialization from Operator.""" op1 = Operator(self.rand_matrix(4, 4)) op2 = Operator(op1) self.assertEqual(op1, op2)
def to_operator(self): """Try to convert channel to a unitary representation Operator.""" mat = _to_operator(self._channel_rep, self._data, *self.dim) return Operator(mat, self.input_dims(), self.output_dims())
def test_equal(self): """Test __eq__ method""" mat = self.rand_matrix(2, 2, real=True) self.assertEqual(Operator(np.array(mat, dtype=complex)), Operator(mat)) mat = self.rand_matrix(4, 4) self.assertEqual(Operator(mat.tolist()), Operator(mat))
def test_ptm_expand_random(self): """Test expand of PTM matrices is correct.""" mats = [self.rand_matrix(2, 2) for _ in range(4)] chans = [PTM(Operator(mat)) for mat in mats] self._compare_expand_to_operator(chans, mats)
def test_data(self): """Test Operator representation string property.""" mat = self.rand_matrix(2, 2) op = Operator(mat) assert_allclose(mat, op.data)
def test_stinespring_compose_random(self): """Test compose of Stinespring matrices is correct.""" mats = [self.rand_matrix(4, 4) for _ in range(4)] chans = [Stinespring(Operator(mat)) for mat in mats] self._compare_compose_to_operator(chans, mats)
def test_rep(self): """Test Operator representation string property.""" op = Operator(self.rand_matrix(2, 2)) self.assertEqual(op.rep, 'Operator')