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 term_reordering.""" 13 14import unittest 15import itertools 16import numpy 17 18from openfermion.hamiltonians import number_operator 19from openfermion.ops.operators import (FermionOperator, BosonOperator, 20 QuadOperator) 21from openfermion.transforms.opconversions import (jordan_wigner, 22 get_fermion_operator) 23from openfermion.testing.testing_utils import random_interaction_operator 24from openfermion.utils import up_then_down 25 26from openfermion.transforms.opconversions.term_reordering import ( 27 normal_ordered, chemist_ordered, reorder) 28 29 30class ChemistOrderingTest(unittest.TestCase): 31 32 def test_convert_forward_back(self): 33 n_qubits = 6 34 random_operator = get_fermion_operator( 35 random_interaction_operator(n_qubits)) 36 chemist_operator = chemist_ordered(random_operator) 37 normalized_chemist = normal_ordered(chemist_operator) 38 difference = normalized_chemist - normal_ordered(random_operator) 39 self.assertAlmostEqual(0., difference.induced_norm()) 40 41 def test_exception(self): 42 n_qubits = 6 43 random_operator = get_fermion_operator( 44 random_interaction_operator(n_qubits)) 45 bad_term = ((2, 1), (3, 1)) 46 random_operator += FermionOperator(bad_term) 47 with self.assertRaises(TypeError): 48 chemist_ordered(random_operator) 49 50 def test_form(self): 51 n_qubits = 6 52 random_operator = get_fermion_operator( 53 random_interaction_operator(n_qubits)) 54 chemist_operator = chemist_ordered(random_operator) 55 for term, _ in chemist_operator.terms.items(): 56 if len(term) == 2 or not len(term): 57 pass 58 else: 59 self.assertTrue(term[0][1]) 60 self.assertTrue(term[2][1]) 61 self.assertFalse(term[1][1]) 62 self.assertFalse(term[3][1]) 63 self.assertTrue(term[0][0] > term[2][0]) 64 self.assertTrue(term[1][0] > term[3][0]) 65 66 67class TestNormalOrdering(unittest.TestCase): 68 69 def test_boson_single_term(self): 70 op = BosonOperator('4 3 2 1') + BosonOperator('3 2') 71 self.assertTrue(op == normal_ordered(op)) 72 73 def test_boson_two_term(self): 74 op_b = BosonOperator(((2, 0), (4, 0), (2, 1)), 88.) 75 normal_ordered_b = normal_ordered(op_b) 76 expected = (BosonOperator(((4, 0),), 88.) + BosonOperator( 77 ((2, 1), (4, 0), (2, 0)), 88.)) 78 self.assertTrue(normal_ordered_b == expected) 79 80 def test_boson_number(self): 81 number_op2 = BosonOperator(((2, 1), (2, 0))) 82 self.assertTrue(number_op2 == normal_ordered(number_op2)) 83 84 def test_boson_number_reversed(self): 85 n_term_rev2 = BosonOperator(((2, 0), (2, 1))) 86 number_op2 = number_operator(3, 2, parity=1) 87 expected = BosonOperator(()) + number_op2 88 self.assertTrue(normal_ordered(n_term_rev2) == expected) 89 90 def test_boson_offsite(self): 91 op = BosonOperator(((3, 1), (2, 0))) 92 self.assertTrue(op == normal_ordered(op)) 93 94 def test_boson_offsite_reversed(self): 95 op = BosonOperator(((3, 0), (2, 1))) 96 expected = BosonOperator(((2, 1), (3, 0))) 97 self.assertTrue(expected == normal_ordered(op)) 98 99 def test_boson_multi(self): 100 op = BosonOperator(((2, 0), (1, 1), (2, 1))) 101 expected = (BosonOperator(((2, 1), (1, 1), (2, 0))) + BosonOperator( 102 ((1, 1),))) 103 self.assertTrue(expected == normal_ordered(op)) 104 105 def test_boson_triple(self): 106 op_132 = BosonOperator(((1, 1), (3, 0), (2, 0))) 107 op_123 = BosonOperator(((1, 1), (2, 0), (3, 0))) 108 op_321 = BosonOperator(((3, 0), (2, 0), (1, 1))) 109 110 self.assertTrue(op_132 == normal_ordered(op_123)) 111 self.assertTrue(op_132 == normal_ordered(op_132)) 112 self.assertTrue(op_132 == normal_ordered(op_321)) 113 114 def test_fermion_single_term(self): 115 op = FermionOperator('4 3 2 1') + FermionOperator('3 2') 116 self.assertTrue(op == normal_ordered(op)) 117 118 def test_fermion_two_term(self): 119 op_b = FermionOperator(((2, 0), (4, 0), (2, 1)), -88.) 120 normal_ordered_b = normal_ordered(op_b) 121 expected = (FermionOperator(((4, 0),), 88.) + FermionOperator( 122 ((2, 1), (4, 0), (2, 0)), 88.)) 123 self.assertTrue(normal_ordered_b == expected) 124 125 def test_fermion_number(self): 126 number_op2 = FermionOperator(((2, 1), (2, 0))) 127 self.assertTrue(number_op2 == normal_ordered(number_op2)) 128 129 def test_fermion_number_reversed(self): 130 n_term_rev2 = FermionOperator(((2, 0), (2, 1))) 131 number_op2 = number_operator(3, 2) 132 expected = FermionOperator(()) - number_op2 133 self.assertTrue(normal_ordered(n_term_rev2) == expected) 134 135 def test_fermion_offsite(self): 136 op = FermionOperator(((3, 1), (2, 0))) 137 self.assertTrue(op == normal_ordered(op)) 138 139 def test_fermion_offsite_reversed(self): 140 op = FermionOperator(((3, 0), (2, 1))) 141 expected = -FermionOperator(((2, 1), (3, 0))) 142 self.assertTrue(expected == normal_ordered(op)) 143 144 def test_fermion_double_create(self): 145 op = FermionOperator(((2, 0), (3, 1), (3, 1))) 146 expected = FermionOperator((), 0.0) 147 self.assertTrue(expected == normal_ordered(op)) 148 149 def test_fermion_double_create_separated(self): 150 op = FermionOperator(((3, 1), (2, 0), (3, 1))) 151 expected = FermionOperator((), 0.0) 152 self.assertTrue(expected == normal_ordered(op)) 153 154 def test_fermion_multi(self): 155 op = FermionOperator(((2, 0), (1, 1), (2, 1))) 156 expected = (-FermionOperator( 157 ((2, 1), (1, 1), (2, 0))) - FermionOperator(((1, 1),))) 158 self.assertTrue(expected == normal_ordered(op)) 159 160 def test_fermion_triple(self): 161 op_132 = FermionOperator(((1, 1), (3, 0), (2, 0))) 162 op_123 = FermionOperator(((1, 1), (2, 0), (3, 0))) 163 op_321 = FermionOperator(((3, 0), (2, 0), (1, 1))) 164 165 self.assertTrue(op_132 == normal_ordered(-op_123)) 166 self.assertTrue(op_132 == normal_ordered(op_132)) 167 self.assertTrue(op_132 == normal_ordered(op_321)) 168 169 def test_quad_single_term(self): 170 op = QuadOperator('p4 p3 p2 p1') + QuadOperator('p3 p2') 171 self.assertTrue(op == normal_ordered(op)) 172 173 op = QuadOperator('q0 p0') - QuadOperator('p0 q0') 174 expected = QuadOperator('', 2.j) 175 self.assertTrue(expected == normal_ordered(op, hbar=2.)) 176 177 def test_quad_two_term(self): 178 op_b = QuadOperator('p0 q0 p3', 88.) 179 normal_ordered_b = normal_ordered(op_b, hbar=2) 180 expected = QuadOperator('p3', -88. * 2j) + QuadOperator( 181 'q0 p0 p3', 88.0) 182 self.assertTrue(normal_ordered_b == expected) 183 184 def test_quad_offsite(self): 185 op = QuadOperator(((3, 'p'), (2, 'q'))) 186 self.assertTrue(op == normal_ordered(op)) 187 188 def test_quad_offsite_reversed(self): 189 op = QuadOperator(((3, 'q'), (2, 'p'))) 190 expected = QuadOperator(((2, 'p'), (3, 'q'))) 191 self.assertTrue(expected == normal_ordered(op)) 192 193 def test_quad_triple(self): 194 op_132 = QuadOperator(((1, 'p'), (3, 'q'), (2, 'q'))) 195 op_123 = QuadOperator(((1, 'p'), (2, 'q'), (3, 'q'))) 196 op_321 = QuadOperator(((3, 'q'), (2, 'q'), (1, 'p'))) 197 198 self.assertTrue(op_132 == normal_ordered(op_123)) 199 self.assertTrue(op_132 == normal_ordered(op_132)) 200 self.assertTrue(op_132 == normal_ordered(op_321)) 201 202 def test_interaction_operator(self): 203 for n_orbitals, real, _ in itertools.product((1, 2, 5), (True, False), 204 range(5)): 205 operator = random_interaction_operator(n_orbitals, real=real) 206 normal_ordered_operator = normal_ordered(operator) 207 expected_qubit_operator = jordan_wigner(operator) 208 actual_qubit_operator = jordan_wigner(normal_ordered_operator) 209 assert expected_qubit_operator == actual_qubit_operator 210 two_body_tensor = normal_ordered_operator.two_body_tensor 211 n_orbitals = len(two_body_tensor) 212 ones = numpy.ones((n_orbitals,) * 2) 213 triu = numpy.triu(ones, 1) 214 shape = (n_orbitals**2, 1) 215 mask = (triu.reshape(shape) * ones.reshape(shape[::-1]) + 216 ones.reshape(shape) * triu.reshape(shape[::-1])).reshape( 217 (n_orbitals,) * 4) 218 assert numpy.allclose(mask * two_body_tensor, 219 numpy.zeros((n_orbitals,) * 4)) 220 for term in normal_ordered_operator: 221 order = len(term) // 2 222 left_term, right_term = term[:order], term[order:] 223 assert all(i[1] == 1 for i in left_term) 224 assert all(i[1] == 0 for i in right_term) 225 assert left_term == tuple(sorted(left_term, reverse=True)) 226 assert right_term == tuple(sorted(right_term, reverse=True)) 227 228 def test_exceptions(self): 229 with self.assertRaises(TypeError): 230 _ = normal_ordered(1) 231 232 233class TestReorder(unittest.TestCase): 234 235 def test_reorder(self): 236 237 def shift_by_one(x, y): 238 return (x + 1) % y 239 240 operator = FermionOperator('1^ 2^ 3 4', -3.17) 241 reordered = reorder(operator, shift_by_one) 242 self.assertEqual(reordered.terms, 243 {((2, 1), (3, 1), (4, 0), (0, 0)): -3.17}) 244 reordered = reorder(operator, shift_by_one, reverse=True) 245 self.assertEqual(reordered.terms, 246 {((0, 1), (1, 1), (2, 0), (3, 0)): -3.17}) 247 248 def test_reorder_boson(self): 249 shift_by_one = lambda x, y: (x + 1) % y 250 operator = BosonOperator('1^ 2^ 3 4', -3.17) 251 reordered = reorder(operator, shift_by_one) 252 self.assertEqual(reordered.terms, 253 {((0, 0), (2, 1), (3, 1), (4, 0)): -3.17}) 254 reordered = reorder(operator, shift_by_one, reverse=True) 255 self.assertEqual(reordered.terms, 256 {((0, 1), (1, 1), (2, 0), (3, 0)): -3.17}) 257 258 def test_reorder_quad(self): 259 shift_by_one = lambda x, y: (x + 1) % y 260 operator = QuadOperator('q1 q2 p3 p4', -3.17) 261 reordered = reorder(operator, shift_by_one) 262 self.assertEqual(reordered.terms, 263 {((0, 'p'), (2, 'q'), (3, 'q'), (4, 'p')): -3.17}) 264 reordered = reorder(operator, shift_by_one, reverse=True) 265 self.assertEqual(reordered.terms, 266 {((0, 'q'), (1, 'q'), (2, 'p'), (3, 'p')): -3.17}) 267 268 def test_up_then_down(self): 269 for LadderOp in (FermionOperator, BosonOperator): 270 operator = LadderOp('1^ 2^ 3 4', -3.17) 271 reordered = reorder(operator, up_then_down) 272 reordered = reorder(reordered, up_then_down, reverse=True) 273 274 self.assertEqual(reordered.terms, operator.terms) 275 self.assertEqual(up_then_down(6, 8), 3) 276 self.assertEqual(up_then_down(3, 8), 5) 277