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.
12"""Tests for verstraete_cirac.py."""
13
14import unittest
15
16from openfermion.hamiltonians import fermi_hubbard
17from openfermion.linalg import get_sparse_operator, get_ground_state
18from openfermion.transforms.opconversions import verstraete_cirac_2d_square
19from openfermion.transforms.opconversions.verstraete_cirac import (
20    coordinates_to_snake_index, snake_index_to_coordinates,
21    stabilizer_local_2d_square)
22
23
24class VerstraeteCirac2dSquareGroundStateTest(unittest.TestCase):
25    """Test that the transform preserves desired ground state properties."""
26
27    def setUp(self):
28        self.x_dimension = 2
29        self.y_dimension = 3
30
31        # Create a Hamiltonian with nearest-neighbor hopping terms
32        self.ferm_op = fermi_hubbard(self.x_dimension, self.y_dimension, 1., 0.,
33                                     0., 0., False, True)
34
35        # Get the ground energy and ground state
36        self.ferm_op_sparse = get_sparse_operator(self.ferm_op)
37        self.ferm_op_ground_energy, self.ferm_op_ground_state = (
38            get_ground_state(self.ferm_op_sparse))
39
40        # Transform the FermionOperator to a QubitOperator
41        self.transformed_op = verstraete_cirac_2d_square(
42            self.ferm_op,
43            self.x_dimension,
44            self.y_dimension,
45            add_auxiliary_hamiltonian=True,
46            snake=False)
47
48        # Get the ground energy and state of the transformed operator
49        self.transformed_sparse = get_sparse_operator(self.transformed_op)
50        self.transformed_ground_energy, self.transformed_ground_state = (
51            get_ground_state(self.transformed_sparse))
52
53    def test_ground_energy(self):
54        """Test that the transformation preserves the ground energy."""
55        self.assertAlmostEqual(self.transformed_ground_energy,
56                               self.ferm_op_ground_energy)
57
58
59class VerstraeteCirac2dSquareOperatorLocalityTest(unittest.TestCase):
60    """Test that the transform results in local qubit operators."""
61
62    def setUp(self):
63        self.x_dimension = 6
64        self.y_dimension = 6
65
66        # Create a Hubbard Hamiltonian
67        self.ferm_op = fermi_hubbard(self.x_dimension, self.y_dimension, 1.0,
68                                     4.0, 0.0, 0.0, False, True)
69
70        # Transform the FermionOperator to a QubitOperator without including
71        # the auxiliary Hamiltonian
72        self.transformed_op_no_aux = verstraete_cirac_2d_square(
73            self.ferm_op,
74            self.x_dimension,
75            self.y_dimension,
76            add_auxiliary_hamiltonian=False,
77            snake=False)
78        self.transformed_op_no_aux.compress()
79
80        # Transform the FermionOperator to a QubitOperator, including
81        # the auxiliary Hamiltonian
82        self.transformed_op_aux = verstraete_cirac_2d_square(
83            self.ferm_op,
84            self.x_dimension,
85            self.y_dimension,
86            add_auxiliary_hamiltonian=True,
87            snake=False)
88        self.transformed_op_aux.compress()
89
90    def test_operator_locality_no_aux(self):
91        """Test that the operators without the auxiliary Hamiltonian
92        are at most 4-local."""
93        for term in self.transformed_op_no_aux.terms:
94            self.assertTrue(len(term) <= 4)
95
96    def test_operator_locality_aux(self):
97        """Test that the operators with the auxiliary Hamiltonian
98        are at most 6-local."""
99        for term in self.transformed_op_aux.terms:
100            self.assertTrue(len(term) <= 6)
101
102
103class ExceptionTest(unittest.TestCase):
104    """Test that exceptions are raised correctly."""
105
106    def test_verstraete_cirac_2d_square(self):
107        ferm_op = fermi_hubbard(3, 2, 1., 0., spinless=True)
108        with self.assertRaises(NotImplementedError):
109            _ = verstraete_cirac_2d_square(ferm_op, 3, 2)
110
111    def test_stabilizer_local_2d_square(self):
112        with self.assertRaises(ValueError):
113            _ = stabilizer_local_2d_square(0, 2, 4, 4)
114
115    def test_coordinates_to_snake_index(self):
116        with self.assertRaises(ValueError):
117            _ = coordinates_to_snake_index(4, 4, 4, 5)
118        with self.assertRaises(ValueError):
119            _ = coordinates_to_snake_index(4, 4, 5, 4)
120
121    def test_snake_index_to_coordinates(self):
122        with self.assertRaises(ValueError):
123            _ = snake_index_to_coordinates(20, 4, 5)
124