1#   Licensed under the Apache License, Version 2.0 (the "License");
2#   you may not use this file except in compliance with the License.
3#   You may obtain a copy of the License at
4#
5#       http://www.apache.org/licenses/LICENSE-2.0
6#
7#   Unless required by applicable law or agreed to in writing, software
8#   distributed under the License is distributed on an "AS IS" BASIS,
9#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10#   See the License for the specific language governing permissions and
11#   limitations under the License.
12import pytest
13import numpy
14import cirq
15import openfermion
16from openfermion.ops.operators import QubitOperator
17
18from openfermion.transforms.opconversions import (qubit_operator_to_pauli_sum)
19from openfermion.transforms.opconversions.qubitoperator_to_paulisum import (
20    _qubit_operator_term_to_pauli_string)
21
22
23def test_function_raises():
24    """Test function raises."""
25    operator = QubitOperator('X0 X1 X2 X3', 1.0)
26    with pytest.raises(TypeError):
27        _qubit_operator_term_to_pauli_string(list(operator.terms.items())[0],
28                                             qubits=0.0)
29    with pytest.raises(TypeError):
30        qubit_operator_to_pauli_sum([5.0])
31
32
33def test_pauli_sum_qubits():
34    """Test PauliSum creates qubits."""
35    operator = QubitOperator('X0 X1 X2 X3', 1.0)
36    pauli_sum = qubit_operator_to_pauli_sum(operator=operator)
37
38    assert list(pauli_sum.qubits) == (cirq.LineQubit.range(4))
39
40
41def test_identity():
42    """Test correct hanlding of Identity."""
43    identity_op = QubitOperator(' ', -0.5)
44    pau_from_qop = _qubit_operator_term_to_pauli_string(
45        term=list(identity_op.terms.items())[0], qubits=cirq.LineQubit.range(2))
46    pauli_str = cirq.PauliString() * (-0.5)
47
48    assert pauli_str == pau_from_qop
49
50
51@pytest.mark.parametrize('qubitop, state_binary',
52                         [(QubitOperator('Z0 Z1', -1.0), '00'),
53                          (QubitOperator('X0 Y1', 1.0), '10')])
54def test_expectation_values(qubitop, state_binary):
55    """Test PauliSum and QubitOperator expectation value."""
56    n_qubits = openfermion.count_qubits(qubitop)
57    state = numpy.zeros(2**n_qubits, dtype='complex64')
58    state[int(state_binary, 2)] = 1.0
59    qubit_map = {cirq.LineQubit(i): i for i in range(n_qubits)}
60
61    pauli_str = _qubit_operator_term_to_pauli_string(
62        term=list(qubitop.terms.items())[0],
63        qubits=cirq.LineQubit.range(n_qubits))
64    op_mat = openfermion.get_sparse_operator(qubitop, n_qubits)
65
66    expct_qop = openfermion.expectation(op_mat, state)
67    expct_pauli = pauli_str.expectation_from_state_vector(state, qubit_map)
68
69    numpy.testing.assert_allclose(expct_qop, expct_pauli)
70
71
72@pytest.mark.parametrize(
73    'qubitop, state_binary',
74    [(QubitOperator('Z0 Z1 Z2 Z3', -1.0) + QubitOperator('X0 Y1 Y2 X3', 1.0),
75      '1100'),
76     (QubitOperator('X0 X3', -1.0) + QubitOperator('Y1 Y2', 1.0), '0000')])
77def test_expectation_values_paulisum(qubitop, state_binary):
78    """Test PauliSum and QubitOperator expectation value."""
79    n_qubits = openfermion.count_qubits(qubitop)
80    state = numpy.zeros(2**n_qubits, dtype='complex64')
81    state[int(state_binary, 2)] = 1.0
82    qubit_map = {cirq.LineQubit(i): i for i in range(n_qubits)}
83
84    pauli_str = qubit_operator_to_pauli_sum(qubitop, list(qubit_map.keys()))
85    op_mat = openfermion.get_sparse_operator(qubitop, n_qubits)
86
87    expct_qop = openfermion.expectation(op_mat, state)
88    expct_pauli = pauli_str.expectation_from_state_vector(state, qubit_map)
89
90    numpy.testing.assert_allclose(expct_qop, expct_pauli)
91