def test_permutation_without_expansion(self, permutation): base = qutip.tensor([qutip.rand_unitary(2) for _ in permutation]) test = gates.expand_operator(base, N=len(permutation), targets=permutation) expected = base.permute(_apply_permutation(permutation)) np.testing.assert_allclose(test.full(), expected.full(), atol=1e-15)
def test_cyclic_permutation(self): operators = [qutip.sigmax(), qutip.sigmaz()] test = gates.expand_operator(qutip.tensor(*operators), N=3, targets=[0, 1], cyclic_permutation=True) base_expected = qutip.tensor(*operators, qutip.qeye(2)) expected = [base_expected.permute(x) for x in [[0, 1, 2], [1, 2, 0], [2, 0, 1]]] assert len(expected) == len(test) for element in expected: assert element in test
def test_general_qubit_expansion(self, n_targets): # Test all permutations with the given number of targets. n_qubits = 5 operation = qutip.rand_unitary(2**n_targets, dims=[[2]*n_targets]*2) for targets in itertools.permutations(range(n_qubits), n_targets): expected = _tensor_with_entanglement([qutip.qeye(2)] * n_qubits, operation, targets) test = gates.expand_operator(operation, n_qubits, targets) np.testing.assert_allclose(test.full(), expected.full(), atol=1e-15)
def measurement_statistics_povm(state, ops, targets=None): r""" Returns measurement statistics (resultant states and probabilities) for a measurement specified by a set of positive operator valued measurements on a specified ket or density matrix. Parameters ---------- state : :class:`.Qobj` The ket or density matrix specifying the state to measure. ops : list of :class:`.Qobj` List of measurement operators :math:`M_i` or kets. Either: 1. specifying a POVM s.t. :math:`E_i = M_i^\dagger M_i` 2. projection operators if ops correspond to projectors (s.t. :math:`E_i = M_i^\dagger = M_i`) 3. kets (transformed to projectors) targets : list of ints, optional Specifies a list of target "qubit" indices on which to apply the measurement using qutip.qip.gates.expand_operator to expand ops into full dimension. Returns ------- collapsed_states : list of :class:`.Qobj` The collapsed states obtained after measuring the qubits and obtaining the qubit specified by the target in the state specified by the index. probabilities : list of floats The probability of measuring a state in a the state specified by the index. """ if all(map(lambda x: x.isket, ops)): ops = [op * op.dag() for op in ops] if targets: N = int(np.log2(state.shape[0])) ops = [expand_operator(op, N=N, targets=targets) for op in ops] for op in ops: _verify_input(op, state) E = [op.dag() * op for op in ops] is_ID = sum(E) if not is_ID == identity(is_ID.dims[0]): raise ValueError("measurement operators must sum to identity") if state.isket: return _measurement_statistics_povm_ket(state, ops) else: return _measurement_statistics_povm_dm(state, ops)
def test_cnot_explicit(self): test = gates.expand_operator(gates.cnot(), 3, [2, 0]).full() expected = np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0]]) np.testing.assert_allclose(test, expected, atol=1e-15)
def test_non_qubit_systems(self, dimensions): n_qubits = len(dimensions) for targets in itertools.permutations(range(n_qubits), 2): operators = [qutip.rand_unitary(dimension) if n in targets else qutip.qeye(dimension) for n, dimension in enumerate(dimensions)] expected = qutip.tensor(*operators) base_test = qutip.tensor(*[operators[x] for x in targets]) test = gates.expand_operator(base_test, N=n_qubits, targets=targets, dims=dimensions) assert test.dims == expected.dims np.testing.assert_allclose(test.full(), expected.full())
def measurement_statistics_observable(state, op, targets=None): """ Return the measurement eigenvalues, eigenstates (or projectors) and measurement probabilities for the given state and measurement operator. Parameters ---------- state : :class:`.Qobj` The ket or density matrix specifying the state to measure. op : :class:`.Qobj` The measurement operator. targets : list of ints, optional Specifies a list of targets "qubit" indices on which to apply the measurement using :func:`qutip.qip.gates.expand_operator` to expand op into full dimension. Returns ------- eigenvalues: list of float The list of eigenvalues of the measurement operator. eigenstates_or_projectors: list of :class:`.Qobj` If the state was a ket, return the eigenstates of the measurement operator. Otherwise return the projectors onto the eigenstates. probabilities: list of float The probability of measuring the state as being in the corresponding eigenstate (and the measurement result being the corresponding eigenvalue). """ if targets: N = int(np.log2(state.shape[0])) op = expand_operator(op, N=N, targets=targets) _verify_input(op, state) eigenvalues, eigenstates = op.eigenstates() if state.isket: probabilities = [(e.dag() * state).norm()**2 for e in eigenstates] return eigenvalues, eigenstates, probabilities else: projectors = [v * v.dag() for v in eigenstates] probabilities = [(p * state).tr() for p in projectors] return eigenvalues, projectors, probabilities
def test_expand_operator(self): """ gate : expand qubits operator to a N qubits system. """ # oper size is N, no expansion oper = tensor(sigmax(), sigmay()) assert_allclose(expand_operator(oper=oper, targets=[0, 1], N=2), oper) assert_allclose(expand_operator(oper=oper, targets=[1, 0], N=2), tensor(sigmay(), sigmax())) # random single qubit gate test, integer as target r = rand_unitary(2) assert_allclose(expand_operator(r, 3, 0), tensor([r, identity(2), identity(2)])) assert_allclose(expand_operator(r, 3, 1), tensor([identity(2), r, identity(2)])) assert_allclose(expand_operator(r, 3, 2), tensor([identity(2), identity(2), r])) # random 2qubits gate test, list as target r2 = rand_unitary(4) r2.dims = [[2, 2], [2, 2]] assert_allclose(expand_operator(r2, 3, [2, 1]), tensor([identity(2), r2.permute([1, 0])])) assert_allclose(expand_operator(r2, 3, [0, 1]), tensor([r2, identity(2)])) assert_allclose(expand_operator(r2, 3, [0, 2]), tensor([r2, identity(2)]).permute([0, 2, 1])) # cnot expantion, qubit 2 control qubit 0 assert_allclose( expand_operator(cnot(), 3, [2, 0]), Qobj([[1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1.], [0., 0., 0., 0., 1., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 1., 0., 0., 0., 0.]], dims=[[2, 2, 2], [2, 2, 2]])) # test expansion with cyclic permutation result = expand_operator(tensor([sigmaz(), sigmax()]), N=3, targets=[2, 0], cyclic_permutation=True) mat1 = tensor(sigmax(), qeye(2), sigmaz()) mat2 = tensor(sigmaz(), sigmax(), qeye(2)) mat3 = tensor(qeye(2), sigmaz(), sigmax()) assert_(mat1 in result) assert_(mat2 in result) assert_(mat3 in result) # test for dimensions other than 2 mat3 = rand_dm(3, density=1.) oper = tensor([sigmax(), mat3]) N = 4 dims = [2, 2, 3, 4] result = expand_operator(oper, N, targets=[0, 2], dims=dims) assert_array_equal(result.dims[0], dims) dims = [3, 2, 4, 2] result = expand_operator(oper, N, targets=[3, 0], dims=dims) assert_array_equal(result.dims[0], dims) dims = [3, 2, 4, 2] result = expand_operator(oper, N, targets=[1, 0], dims=dims) assert_array_equal(result.dims[0], dims)