def test_model_integration_with_constant(self): # Compute Hamiltonian in both momentum and position space. length_scale = 0.7 grid = Grid(dimensions=2, length=3, scale=length_scale) spinless = True # Include the Madelung constant in the momentum but not the position # Hamiltonian. momentum_hamiltonian = jellium_model(grid, spinless, True, include_constant=True) position_hamiltonian = jellium_model(grid, spinless, False) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_hamiltonian) jw_position = jordan_wigner(position_hamiltonian) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm momentum spectrum is shifted 2.8372 / length_scale higher. max_difference = numpy.amax(momentum_spectrum - position_spectrum) min_difference = numpy.amax(momentum_spectrum - position_spectrum) self.assertAlmostEqual(max_difference, 2.8372 / length_scale) self.assertAlmostEqual(min_difference, 2.8372 / length_scale)
def test_bk_jw_majoranas(self): # Check if the Majorana operators have the same spectrum # irrespectively of the transform. n_qubits = 7 a = FermionOperator(((1, 0), )) a_dag = FermionOperator(((1, 1), )) c = a + a_dag d = 1j * (a_dag - a) c_spins = [jordan_wigner(c), bravyi_kitaev(c)] d_spins = [jordan_wigner(d), bravyi_kitaev(d)] c_sparse = [ get_sparse_operator(c_spins[0]), get_sparse_operator(c_spins[1]) ] d_sparse = [ get_sparse_operator(d_spins[0]), get_sparse_operator(d_spins[1]) ] c_spectrum = [eigenspectrum(c_spins[0]), eigenspectrum(c_spins[1])] d_spectrum = [eigenspectrum(d_spins[0]), eigenspectrum(d_spins[1])] self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(d_spectrum[0] - d_spectrum[1])))
def get_interaction_rdm(qubit_operator, n_qubits=None): """Build an InteractionRDM from measured qubit operators. Returns: An InteractionRDM object. """ # Avoid circular import. from fermilib.transforms import jordan_wigner if n_qubits is None: n_qubits = count_qubits(qubit_operator) one_rdm = numpy.zeros((n_qubits, ) * 2, dtype=complex) two_rdm = numpy.zeros((n_qubits, ) * 4, dtype=complex) # One-RDM. for i, j in itertools.product(range(n_qubits), repeat=2): transformed_operator = jordan_wigner(FermionOperator(((i, 1), (j, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: one_rdm[i, j] += coefficient * qubit_operator.terms[term] # Two-RDM. for i, j, k, l in itertools.product(range(n_qubits), repeat=4): transformed_operator = jordan_wigner( FermionOperator(((i, 1), (j, 1), (k, 0), (l, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: two_rdm[i, j, k, l] += coefficient * qubit_operator.terms[term] return InteractionRDM(one_rdm, two_rdm)
def test_plane_wave_hamiltonian_integration(self): length_set = [3, 4] spinless_set = [True, False] geometry = [('H', (0, )), ('H', (0.8, ))] length_scale = 1.1 for l in length_set: for spinless in spinless_set: grid = Grid(dimensions=1, scale=length_scale, length=l) h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless, True, include_constant=True) h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless, False) jw_h_plane_wave = jordan_wigner(h_plane_wave) jw_h_dual_basis = jordan_wigner(h_dual_basis) h_plane_wave_spectrum = eigenspectrum(jw_h_plane_wave) h_dual_basis_spectrum = eigenspectrum(jw_h_dual_basis) max_diff = numpy.amax(h_plane_wave_spectrum - h_dual_basis_spectrum) min_diff = numpy.amin(h_plane_wave_spectrum - h_dual_basis_spectrum) self.assertAlmostEqual(max_diff, 2.8372 / length_scale) self.assertAlmostEqual(min_diff, 2.8372 / length_scale)
def test_identity(self): n_qubits = 5 transmed_i = reverse_jordan_wigner(self.identity, n_qubits) expected_i = FermionOperator(()) self.assertTrue(transmed_i.isclose(expected_i)) retransmed_i = jordan_wigner(transmed_i) self.assertTrue(self.identity.isclose(retransmed_i))
def test_jordan_wigner_position_jellium(self): # Parameters. n_dimensions = 2 grid_length = 3 length_scale = 1. spinless = 1 # Compute fermionic Hamiltonian. fermion_hamiltonian = jellium_model( n_dimensions, grid_length, length_scale, spinless, 0) qubit_hamiltonian = jordan_wigner(fermion_hamiltonian) # Compute Jordan-Wigner Hamiltonian. test_hamiltonian = jordan_wigner_position_jellium( n_dimensions, grid_length, length_scale, spinless) # Make sure Hamiltonians are the same. self.assertTrue(test_hamiltonian.isclose(qubit_hamiltonian)) # Check number of terms. n_qubits = count_qubits(qubit_hamiltonian) if spinless: paper_n_terms = 1 - .5 * n_qubits + 1.5 * (n_qubits ** 2) else: paper_n_terms = 1 - .5 * n_qubits + n_qubits ** 2 num_nonzeros = sum(1 for coeff in qubit_hamiltonian.terms.values() if coeff != 0.0) self.assertTrue(num_nonzeros <= paper_n_terms)
def test_jordan_wigner_dual_basis_jellium(self): # Parameters. grid = Grid(dimensions=2, length=3, scale=1.) spinless = True # Compute fermionic Hamiltonian. Include then subtract constant. fermion_hamiltonian = dual_basis_jellium_model(grid, spinless, include_constant=True) qubit_hamiltonian = jordan_wigner(fermion_hamiltonian) qubit_hamiltonian -= QubitOperator((), 2.8372) # Compute Jordan-Wigner Hamiltonian. test_hamiltonian = jordan_wigner_dual_basis_jellium(grid, spinless) # Make sure Hamiltonians are the same. self.assertTrue(test_hamiltonian.isclose(qubit_hamiltonian)) # Check number of terms. n_qubits = count_qubits(qubit_hamiltonian) if spinless: paper_n_terms = 1 - .5 * n_qubits + 1.5 * (n_qubits**2) num_nonzeros = sum(1 for coeff in qubit_hamiltonian.terms.values() if coeff != 0.0) self.assertTrue(num_nonzeros <= paper_n_terms)
def setUp(self): self.n_qubits = 5 self.fermion_term = FermionOperator('1^ 2^ 3 4', -3.17) self.fermion_operator = self.fermion_term + hermitian_conjugated( self.fermion_term) self.qubit_operator = jordan_wigner(self.fermion_operator) self.interaction_operator = get_interaction_operator( self.fermion_operator)
def test_zero(self): n_qubits = 5 transmed_i = reverse_jordan_wigner(QubitOperator(), n_qubits) expected_i = FermionOperator() self.assertTrue(transmed_i.isclose(expected_i)) retransmed_i = jordan_wigner(transmed_i) self.assertTrue(expected_i.isclose(retransmed_i))
def test_model_integration(self): # Compute Hamiltonian in both momentum and position space. grid = Grid(dimensions=2, length=3, scale=1.0) spinless = True momentum_hamiltonian = jellium_model(grid, spinless, True) position_hamiltonian = jellium_model(grid, spinless, False) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_hamiltonian) jw_position = jordan_wigner(position_hamiltonian) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_potential_integration(self): # Compute potential energy operator in momentum and position space. grid = Grid(dimensions=2, length=3, scale=2.) spinless = 1 momentum_potential = plane_wave_potential(grid, spinless) position_potential = dual_basis_potential(grid, spinless) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_potential) jw_position = jordan_wigner(position_potential) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_kinetic_integration(self): # Compute kinetic energy operator in both momentum and position space. grid = Grid(dimensions=2, length=2, scale=3.) spinless = False momentum_kinetic = plane_wave_kinetic(grid, spinless) position_kinetic = dual_basis_kinetic(grid, spinless) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_kinetic) jw_position = jordan_wigner(position_kinetic) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_get_qubit_expectations(self): qubit_operator = jordan_wigner(self.hamiltonian) qubit_expectations = self.rdm.get_qubit_expectations(qubit_operator) test_energy = qubit_operator.terms[()] for qubit_term in qubit_expectations.terms: term_coefficient = qubit_operator.terms[qubit_term] test_energy += (term_coefficient * qubit_expectations.terms[qubit_term]) self.assertLess(abs(test_energy - self.cisd_energy), EQ_TOLERANCE)
def test_z(self): pauli_z = QubitOperator(((2, 'Z'), )) transmed_z = reverse_jordan_wigner(pauli_z) expected = (FermionOperator(()) + FermionOperator( ((2, 1), (2, 0)), -2.)) self.assertTrue(transmed_z.isclose(expected)) retransmed_z = jordan_wigner(transmed_z) self.assertTrue(pauli_z.isclose(retransmed_z))
def test_xy(self): xy = QubitOperator(((4, 'X'), (5, 'Y')), -2.j) transmed_xy = reverse_jordan_wigner(xy) retransmed_xy = jordan_wigner(transmed_xy) expected1 = -2j * (FermionOperator(((4, 1), ), 1j) - FermionOperator( ((4, 0), ), 1j)) expected2 = (FermionOperator(((5, 1), )) - FermionOperator(((5, 0), ))) expected = expected1 * expected2 self.assertTrue(xy.isclose(retransmed_xy)) self.assertTrue( normal_ordered(transmed_xy).isclose(normal_ordered(expected)))
def test_bk_jw_number_operator(self): # Check if number operator has the same spectrum in both # BK and JW representations n = number_operator(1, 0) jw_n = jordan_wigner(n) bk_n = bravyi_kitaev(n) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_n) bk_spectrum = eigenspectrum(bk_n) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_yy(self): yy = QubitOperator(((2, 'Y'), (3, 'Y')), 2.) transmed_yy = reverse_jordan_wigner(yy) retransmed_yy = jordan_wigner(transmed_yy) expected1 = -(FermionOperator(((2, 1), ), 2.) + FermionOperator( ((2, 0), ), 2.)) expected2 = (FermionOperator(((3, 1), )) - FermionOperator(((3, 0), ))) expected = expected1 * expected2 self.assertTrue(yy.isclose(retransmed_yy)) self.assertTrue( normal_ordered(transmed_yy).isclose(normal_ordered(expected)))
def test_kinetic_integration(self): # Compute kinetic energy operator in both momentum and position space. n_dimensions = 2 grid_length = 2 length_scale = 3. spinless = 0 momentum_kinetic = momentum_kinetic_operator( n_dimensions, grid_length, length_scale, spinless) position_kinetic = position_kinetic_operator( n_dimensions, grid_length, length_scale, spinless) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_kinetic) jw_position = jordan_wigner(position_kinetic) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_model_integration(self): # Compute Hamiltonian in both momentum and position space. n_dimensions = 2 grid_length = 3 length_scale = 1. spinless = 1 momentum_hamiltonian = jellium_model( n_dimensions, grid_length, length_scale, spinless, 1) position_hamiltonian = jellium_model( n_dimensions, grid_length, length_scale, spinless, 0) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_hamiltonian) jw_position = jordan_wigner(position_hamiltonian) momentum_spectrum = eigenspectrum(jw_momentum) position_spectrum = eigenspectrum(jw_position) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_bk_jw_number_operator_scaled(self): # Check if number operator has the same spectrum in both # JW and BK representations n_qubits = 1 n = number_operator(n_qubits, 0, coefficient=2) # eigenspectrum (0,2) jw_n = jordan_wigner(n) bk_n = bravyi_kitaev(n) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_n) bk_spectrum = eigenspectrum(bk_n) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_bk_jw_hopping_operator(self): # Check if the spectrum fits for a single hoppping operator n_qubits = 5 ho = FermionOperator(((1, 1), (4, 0))) + FermionOperator( ((4, 1), (1, 0))) jw_ho = jordan_wigner(ho) bk_ho = bravyi_kitaev(ho) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_ho) bk_spectrum = eigenspectrum(bk_ho) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_xx(self): xx = QubitOperator(((3, 'X'), (4, 'X')), 2.) transmed_xx = reverse_jordan_wigner(xx) retransmed_xx = jordan_wigner(transmed_xx) expected1 = (FermionOperator(((3, 1), ), 2.) - FermionOperator( ((3, 0), ), 2.)) expected2 = (FermionOperator(((4, 1), ), 1.) + FermionOperator( ((4, 0), ), 1.)) expected = expected1 * expected2 self.assertTrue(xx.isclose(retransmed_xx)) self.assertTrue( normal_ordered(transmed_xx).isclose(normal_ordered(expected)))
def test_yx(self): yx = QubitOperator(((0, 'Y'), (1, 'X')), -0.5) transmed_yx = reverse_jordan_wigner(yx) retransmed_yx = jordan_wigner(transmed_yx) expected1 = 1j * (FermionOperator(((0, 1), )) + FermionOperator( ((0, 0), ))) expected2 = -0.5 * (FermionOperator(((1, 1), )) + FermionOperator( ((1, 0), ))) expected = expected1 * expected2 self.assertTrue(yx.isclose(retransmed_yx)) self.assertTrue( normal_ordered(transmed_yx).isclose(normal_ordered(expected)))
def test_u_operator_integration(self): n_dimensions = 1 length_scale = 1 grid_length = 3 spinless_set = [True, False] nuclear_charges = numpy.empty((3)) nuclear_charges[0] = 1 nuclear_charges[1] = -3 nuclear_charges[2] = 2 for spinless in spinless_set: u_plane_wave = plane_wave_u_operator( n_dimensions, grid_length, length_scale, nuclear_charges, spinless) u_dual_basis = dual_basis_u_operator( n_dimensions, grid_length, length_scale, nuclear_charges, spinless) jw_u_plane_wave = jordan_wigner(u_plane_wave) jw_u_dual_basis = jordan_wigner(u_dual_basis) u_plane_wave_spectrum = eigenspectrum(jw_u_plane_wave) u_dual_basis_spectrum = eigenspectrum(jw_u_dual_basis) diff = numpy.amax(numpy.absolute( u_plane_wave_spectrum - u_dual_basis_spectrum)) self.assertAlmostEqual(diff, 0)
def test_jordan_wigner_dual_basis_hamiltonian(self): grid = Grid(dimensions=2, length=3, scale=1.) spinless = True geometry = [('H', (0, 0)), ('H', (0.5, 0.8))] fermion_hamiltonian = plane_wave_hamiltonian(grid, geometry, spinless, False, include_constant=True) qubit_hamiltonian = jordan_wigner(fermion_hamiltonian) test_hamiltonian = jordan_wigner_dual_basis_hamiltonian( grid, geometry, spinless, include_constant=True) self.assertTrue(test_hamiltonian.isclose(qubit_hamiltonian))
def test_qubit_jw_fermion_integration(self): # Initialize a random fermionic operator. fermion_operator = FermionOperator(((3, 1), (2, 1), (1, 0), (0, 0)), -4.3) fermion_operator += FermionOperator(((3, 1), (1, 0)), 8.17) fermion_operator += 3.2 * FermionOperator() # Map to qubits and compare matrix versions. qubit_operator = jordan_wigner(fermion_operator) qubit_sparse = get_sparse_operator(qubit_operator) qubit_spectrum = sparse_eigenspectrum(qubit_sparse) fermion_sparse = jordan_wigner_sparse(fermion_operator) fermion_spectrum = sparse_eigenspectrum(fermion_sparse) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(fermion_spectrum - qubit_spectrum)))
def test_bk_jw_integration(self): # This is a legacy test, which was a minimal failing example when # optimization for hermitian operators was used. n_qubits = 4 # Minimal failing example: fo = FermionOperator(((3, 1), )) jw = jordan_wigner(fo) bk = bravyi_kitaev(fo) jw_spectrum = eigenspectrum(jw) bk_spectrum = eigenspectrum(bk) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_bk_jw_number_operators(self): # Check if a number operator has the same spectrum in both # JW and BK representations n_qubits = 2 n1 = number_operator(n_qubits, 0) n2 = number_operator(n_qubits, 1) n = n1 + n2 jw_n = jordan_wigner(n) bk_n = bravyi_kitaev(n) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_n) bk_spectrum = eigenspectrum(bk_n) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_bk_jw_integration_original(self): # This is a legacy test, which was an example proposed by Ryan, # failing when optimization for hermitian operators was used. n_qubits = 5 fermion_operator = FermionOperator(((3, 1), (2, 1), (1, 0), (0, 0)), -4.3) fermion_operator += FermionOperator(((3, 1), (1, 0)), 8.17) fermion_operator += 3.2 * FermionOperator() # Map to qubits and compare matrix versions. jw_qubit_operator = jordan_wigner(fermion_operator) bk_qubit_operator = bravyi_kitaev(fermion_operator) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_qubit_operator) bk_spectrum = eigenspectrum(bk_qubit_operator) self.assertAlmostEqual(0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def benchmark_molecular_operator_jordan_wigner(n_qubits): """Test speed with which molecular operators transform to qubit operators. Args: n_qubits: The size of the molecular operator instance. Ideally, we would be able to transform to a qubit operator for 50 qubit instances in less than a minute. We are way too slow right now. Returns: runtime: The number of seconds required to make the conversion. """ # Get an instance of InteractionOperator. molecular_operator = artificial_molecular_operator(n_qubits) # Convert to a qubit operator. start = time.time() qubit_operator = jordan_wigner(molecular_operator) end = time.time() # Return runtime. runtime = end - start return runtime