def setUp(self): self.x_dimension = 2 self.y_dimension = 3 # Create a Hamiltonian with nearest-neighbor hopping terms self.ferm_op = fermi_hubbard(self.x_dimension, self.y_dimension, 1., 0., 0., 0., False, True) # Get the ground energy and ground state self.ferm_op_sparse = get_sparse_operator(self.ferm_op) self.ferm_op_ground_energy, self.ferm_op_ground_state = ( get_ground_state(self.ferm_op_sparse)) # Transform the FermionOperator to a QubitOperator self.transformed_op = verstraete_cirac_2d_square( self.ferm_op, self.x_dimension, self.y_dimension, add_auxiliary_hamiltonian=True, snake=False) # Get the ground energy and state of the transformed operator self.transformed_sparse = get_sparse_operator(self.transformed_op) self.transformed_ground_energy, self.transformed_ground_state = ( get_ground_state(self.transformed_sparse))
def test_from_integrals_to_qubit(self): hamiltonian = jordan_wigner(self.molecule.get_molecular_hamiltonian()) doci_hamiltonian = DOCIHamiltonian.from_integrals( constant=self.molecule.nuclear_repulsion, one_body_integrals=self.molecule.one_body_integrals, two_body_integrals=self.molecule.two_body_integrals).qubit_operator hamiltonian_matrix = get_sparse_operator(hamiltonian).toarray() doci_hamiltonian_matrix = get_sparse_operator( doci_hamiltonian).toarray() diagonal = numpy.real(numpy.diag(hamiltonian_matrix)) doci_diagonal = numpy.real(numpy.diag(doci_hamiltonian_matrix)) position_of_doci_diag_in_h = [0] * len(doci_diagonal) for idx, doci_eigval in enumerate(doci_diagonal): closest_in_diagonal = None for idx2, eig in enumerate(diagonal): if closest_in_diagonal is None or abs(eig - doci_eigval) < abs( closest_in_diagonal - doci_eigval): closest_in_diagonal = eig position_of_doci_diag_in_h[idx] = idx2 assert abs(closest_in_diagonal - doci_eigval) < EQ_TOLERANCE, ( "Value " + str(doci_eigval) + " of the DOCI Hamiltonian " + "diagonal did not appear in the diagonal of the full " + "Hamiltonian. The closest value was " + str(closest_in_diagonal)) sub_matrix = hamiltonian_matrix[numpy.ix_(position_of_doci_diag_in_h, position_of_doci_diag_in_h)] assert numpy.allclose(doci_hamiltonian_matrix, sub_matrix), ( "The coupling between the DOCI states in the DOCI Hamiltonian " + "should be identical to that between these states in the full " + "Hamiltonian but the DOCI hamiltonian matrix\n" + str(doci_hamiltonian_matrix) + "\ndoes not match the corresponding sub-matrix of the full " + "Hamiltonian\n" + str(sub_matrix))
def test_model_integration_with_constant(self): # Compute Hamiltonian in both momentum and position space. length_scale = 0.7 for length in [2, 3]: grid = Grid(dimensions=2, length=length, scale=length_scale) spinless = True # Include 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) # Confirm they are Hermitian momentum_hamiltonian_operator = ( get_sparse_operator(momentum_hamiltonian)) self.assertTrue(is_hermitian(momentum_hamiltonian_operator)) position_hamiltonian_operator = ( get_sparse_operator(position_hamiltonian)) self.assertTrue(is_hermitian(position_hamiltonian_operator)) # 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_plane_wave_hamiltonian_integration(self): length_set = [2, 3, 4] spinless_set = [True, False] length_scale = 1.1 for geometry in [[('H', (0,)), ('H', (0.8,))], [('H', (0.1,))], [('H', (0.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=False) h_dual_basis = plane_wave_hamiltonian( grid, geometry, spinless, False, include_constant=False) # Test for Hermiticity plane_wave_operator = get_sparse_operator(h_plane_wave) dual_operator = get_sparse_operator(h_dual_basis) self.assertTrue(is_hermitian((plane_wave_operator))) self.assertTrue(is_hermitian(dual_operator)) 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 = np.amax(h_plane_wave_spectrum - h_dual_basis_spectrum) min_diff = np.amin(h_plane_wave_spectrum - h_dual_basis_spectrum) self.assertAlmostEqual(max_diff, 0) self.assertAlmostEqual(min_diff, 0)
def test_potential_integration(self): # Compute potential energy operator in momentum and position space. for length in [2, 3]: grid = Grid(dimensions=2, length=length, scale=2.) spinless = True momentum_potential = plane_wave_potential(grid, spinless) position_potential = dual_basis_potential(grid, spinless) # Confirm they are Hermitian momentum_potential_operator = ( get_sparse_operator(momentum_potential)) self.assertTrue(is_hermitian(momentum_potential_operator)) position_potential_operator = ( get_sparse_operator(position_potential)) self.assertTrue(is_hermitian(position_potential_operator)) # 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_model_integration(self): # Compute Hamiltonian in both momentum and position space. for length in [2, 3]: grid = Grid(dimensions=2, length=length, scale=1.0) spinless = True momentum_hamiltonian = jellium_model(grid, spinless, True) position_hamiltonian = jellium_model(grid, spinless, False) # Confirm they are Hermitian momentum_hamiltonian_operator = ( get_sparse_operator(momentum_hamiltonian)) self.assertTrue(is_hermitian(momentum_hamiltonian_operator)) position_hamiltonian_operator = ( get_sparse_operator(position_hamiltonian)) self.assertTrue(is_hermitian(position_hamiltonian_operator)) # 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_hf_state_energy_same_in_plane_wave_and_dual_basis(self): grid_length = 4 dimension = 1 wigner_seitz_radius = 10.0 spinless = False n_orbitals = grid_length**dimension if not spinless: n_orbitals *= 2 n_particles = n_orbitals // 2 length_scale = wigner_seitz_length_scale(wigner_seitz_radius, n_particles, dimension) grid = Grid(dimension, grid_length, length_scale) hamiltonian = jellium_model(grid, spinless) hamiltonian_dual_basis = jellium_model(grid, spinless, plane_wave=False) # Get the Hamiltonians as sparse operators. hamiltonian_sparse = get_sparse_operator(hamiltonian) hamiltonian_dual_sparse = get_sparse_operator(hamiltonian_dual_basis) hf_state = hartree_fock_state_jellium(grid, n_particles, spinless, plane_wave=True) hf_state_dual = hartree_fock_state_jellium(grid, n_particles, spinless, plane_wave=False) E_HF_plane_wave = expectation(hamiltonian_sparse, hf_state) E_HF_dual = expectation(hamiltonian_dual_sparse, hf_state_dual) self.assertAlmostEqual(E_HF_dual, E_HF_plane_wave)
def test_fermionic_hamiltonian_from_integrals(self): constant = self.molecule.nuclear_repulsion doci_constant = constant hc, hr1, hr2 = get_doci_from_integrals( self.molecule.one_body_integrals, self.molecule.two_body_integrals) doci = DOCIHamiltonian(doci_constant, hc, hr1, hr2) doci_qubit_op = doci.qubit_operator doci_mat = get_sparse_operator(doci_qubit_op).toarray() #doci_eigvals, doci_eigvecs = numpy.linalg.eigh(doci_mat) doci_eigvals, _ = numpy.linalg.eigh(doci_mat) tensors = doci.n_body_tensors one_body_tensors, two_body_tensors = tensors[(1, 0)], tensors[(1, 1, 0, 0)] fermion_op1 = get_fermion_operator( InteractionOperator(constant, one_body_tensors, 0. * two_body_tensors)) fermion_op2 = get_fermion_operator( InteractionOperator(0, 0 * one_body_tensors, 0.5 * two_body_tensors)) import openfermion as of fermion_op1_jw = of.transforms.jordan_wigner(fermion_op1) fermion_op2_jw = of.transforms.jordan_wigner(fermion_op2) fermion_op_jw = fermion_op1_jw + fermion_op2_jw #fermion_eigvals, fermion_eigvecs = numpy.linalg.eigh( # get_sparse_operator(fermion_op_jw).toarray()) fermion_eigvals, _ = numpy.linalg.eigh( get_sparse_operator(fermion_op_jw).toarray()) for eigval in doci_eigvals: assert any(abs(fermion_eigvals - eigval) < 1e-6), "The DOCI spectrum should \ have been contained in the spectrum of the fermionic operators" fermion_diagonal = get_sparse_operator( fermion_op_jw).toarray().diagonal() qubit_diagonal = doci_mat.diagonal() assert numpy.isclose( fermion_diagonal[0], qubit_diagonal[0] ) and numpy.isclose( fermion_diagonal[-1], qubit_diagonal[-1] ), "The first and last elements of hte qubit and fermionic diagonal of \ the Hamiltonian maxtrix should be the same as the vaccum should be \ mapped to the computational all zero state and the completely filled \ state should be mapped to the all one state" print(fermion_diagonal) print(qubit_diagonal)
def test_circuit_generation_and_accuracy(): for dim in range(2, 10): qubits = cirq.LineQubit.range(dim) u_generator = numpy.random.random( (dim, dim)) + 1j * numpy.random.random((dim, dim)) u_generator = u_generator - numpy.conj(u_generator).T assert numpy.allclose(-1 * u_generator, numpy.conj(u_generator).T) unitary = scipy.linalg.expm(u_generator) circuit = cirq.Circuit() circuit.append(optimal_givens_decomposition(qubits, unitary)) fermion_generator = QubitOperator(()) * 0.0 for i, j in product(range(dim), repeat=2): fermion_generator += jordan_wigner( FermionOperator(((i, 1), (j, 0)), u_generator[i, j])) true_unitary = scipy.linalg.expm( get_sparse_operator(fermion_generator).toarray()) assert numpy.allclose(true_unitary.conj().T.dot(true_unitary), numpy.eye(2**dim, dtype=complex)) test_unitary = cirq.unitary(circuit) assert numpy.isclose( abs(numpy.trace(true_unitary.conj().T.dot(test_unitary))), 2**dim)
def ansatz_element_gradient(ansatz_element, var_parameters, ansatz, q_system, cache=None, init_state_qasm=None, excited_state=0): excitations_generators = ansatz_element.excitations_generators exc_gen_sparse_matrices = [] for exc_gen in excitations_generators: exc_gen_sparse_matrices.append( get_sparse_operator(exc_gen, n_qubits=q_system.n_qubits)) exc_gen_sparse_matrix = sum(exc_gen_sparse_matrices) H_sparse_matrix = QiskitSimBackend.ham_sparse_matrix( q_system, excited_state=excited_state) commutator_sparse_matrix = H_sparse_matrix * exc_gen_sparse_matrix - exc_gen_sparse_matrix * H_sparse_matrix statevector = QiskitSimBackend.statevector_from_ansatz( ansatz, var_parameters, q_system.n_qubits, q_system.n_electrons, init_state_qasm=init_state_qasm) sparse_statevector = scipy.sparse.csr_matrix(statevector) grad = sparse_statevector.dot(commutator_sparse_matrix).dot( sparse_statevector.conj().transpose()).todense()[0, 0] assert grad.imag < config.floating_point_accuracy return grad.real
def setUp(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = 'sto-3g' multiplicity = 1 filename = os.path.join(DATA_DIRECTORY, 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(geometry, basis, multiplicity, filename=filename) self.molecule.load() # Get molecular Hamiltonian. self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian() # Get FCI RDM. self.fci_rdm = self.molecule.get_molecular_rdm(use_fci=1) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get fermion Hamiltonian. self.fermion_hamiltonian = normal_ordered( get_fermion_operator(self.molecular_hamiltonian)) # Get qubit Hamiltonian. self.qubit_hamiltonian = jordan_wigner(self.fermion_hamiltonian) # Get the sparse matrix. self.hamiltonian_matrix = get_sparse_operator( self.molecular_hamiltonian)
def tfd_exact(N, TFD_model, int_dict): ''' Solves the TFD model exactly ''' J_L_tens = TFD_model[0] J_R_tens = TFD_model[1] L_indices = range(0, 2*N) R_indices = range(2*N, 4*N) SYK_L_indices = list(permutations(L_indices,4)) SYK_R_indices = list(permutations(R_indices,4)) int_indices = [(l, r) for l, r in zip(L_indices, R_indices)] #print(SYK_L_indices) #print() #print(SYK_R_indices) H_L = convert_H_majorana_to_qubit_L(SYK_L_indices, J_L_tens) H_R = convert_H_majorana_to_qubit_R(SYK_R_indices, J_R_tens, N) H_int = convert_H_majorana_to_qubit_L(int_indices, int_dict) total_ham = H_L + H_R + H_int matrix_ham = get_sparse_operator(total_ham) # todense() allows for ED # Diagonalize qubit hamiltonian to compare the spectrum of variational energy e, v = np.linalg.eigh(matrix_ham.todense()) return e[:10]
def test_hf_state_energy_close_to_ground_energy_at_high_density(self): grid_length = 8 dimension = 1 spinless = True n_particles = grid_length**dimension // 2 # High density -> small length_scale. length_scale = 0.25 grid = Grid(dimension, grid_length, length_scale) hamiltonian = jellium_model(grid, spinless) hamiltonian_sparse = get_sparse_operator(hamiltonian) hf_state = hartree_fock_state_jellium(grid, n_particles, spinless, plane_wave=True) restricted_hamiltonian = jw_number_restrict_operator( hamiltonian_sparse, n_particles) E_g = get_ground_state(restricted_hamiltonian)[0] E_HF_plane_wave = expectation(hamiltonian_sparse, hf_state) self.assertAlmostEqual(E_g, E_HF_plane_wave, places=5)
def test_hf_state_plane_wave_basis_lowest_single_determinant_state(self): grid_length = 7 dimension = 1 spinless = True n_particles = 4 length_scale = 2.0 grid = Grid(dimension, grid_length, length_scale) hamiltonian = jellium_model(grid, spinless) hamiltonian_sparse = get_sparse_operator(hamiltonian) hf_state = hartree_fock_state_jellium(grid, n_particles, spinless, plane_wave=True) HF_energy = expectation(hamiltonian_sparse, hf_state) for occupied_orbitals in permutations([1] * n_particles + [0] * (grid_length - n_particles)): state_index = numpy.sum(2**numpy.array(occupied_orbitals)) HF_competitor = numpy.zeros(2**grid_length) HF_competitor[state_index] = 1.0 self.assertLessEqual(HF_energy, expectation(hamiltonian_sparse, HF_competitor))
def test_richardson_gaudin_hamiltonian(g, n_qubits, expected): rg = RichardsonGaudin(g, n_qubits) rg_qubit = rg.qubit_operator assert rg_qubit == expected assert np.array_equal( np.sort(np.unique(get_sparse_operator(rg_qubit).diagonal())), 2 * np.array(list(range((n_qubits + 1) * n_qubits // 2 + 1))))
def setUp(self): # Set up molecule. geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] basis = 'sto-3g' multiplicity = 1 filename = os.path.join(THIS_DIRECTORY, 'data', 'H1-Li1_sto-3g_singlet_1.45') self.molecule = MolecularData(geometry, basis, multiplicity, filename=filename) self.molecule.load() # Get molecular Hamiltonian self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian() self.molecular_hamiltonian_no_core = ( self.molecule.get_molecular_hamiltonian( occupied_indices=[0], active_indices=range(1, self.molecule.n_orbitals))) # Get FCI RDM. self.fci_rdm = self.molecule.get_molecular_rdm(use_fci=1) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get fermion Hamiltonian. self.fermion_hamiltonian = normal_ordered( get_fermion_operator(self.molecular_hamiltonian)) # Get qubit Hamiltonian. self.qubit_hamiltonian = jordan_wigner(self.fermion_hamiltonian) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get matrix form. self.hamiltonian_matrix = get_sparse_operator( self.molecular_hamiltonian) self.hamiltonian_matrix_no_core = get_sparse_operator( self.molecular_hamiltonian_no_core)
def tfd_exact(N, J): ''' Solves the TFD model exactly ''' indices = list(permutations(range(0, 2 * N), 4)) ham = convert_H_majorana_to_qubit(indices, J) matrix_ham = get_sparse_operator(ham) # todense() allows for ED # Diagonalize qubit hamiltonian to compare the spectrum of variational energy e, v = np.linalg.eigh(matrix_ham.todense()) return e[:10]
def test_bravyi_kitaev_fast_generate_fermions(self): n_qubits = count_qubits(self.molecular_hamiltonian) # test for generating two fermions edge_matrix = bksf.bravyi_kitaev_fast_edge_matrix( self.molecular_hamiltonian) edge_matrix_indices = numpy.array( numpy.nonzero( numpy.triu(edge_matrix) - numpy.diag(numpy.diag(edge_matrix)))) fermion_generation_operator = bksf.generate_fermions( edge_matrix_indices, 2, 3) fermion_generation_sp_matrix = get_sparse_operator( fermion_generation_operator) fermion_generation_matrix = fermion_generation_sp_matrix.toarray() bksf_vacuum_state_operator = bksf.vacuum_operator(edge_matrix_indices) bksf_vacuum_state_sp_matrix = get_sparse_operator( bksf_vacuum_state_operator) bksf_vacuum_state_matrix = bksf_vacuum_state_sp_matrix.toarray() vacuum_state = numpy.zeros((2**(n_qubits), 1)) vacuum_state[0] = 1. bksf_vacuum_state = numpy.dot(bksf_vacuum_state_matrix, vacuum_state) two_fermion_state = numpy.dot(fermion_generation_matrix, bksf_vacuum_state) # using total number operator to check the number of fermions generated tot_number_operator = bksf.number_operator(self.molecular_hamiltonian) number_operator_sp_matrix = get_sparse_operator(tot_number_operator) number_operator_matrix = number_operator_sp_matrix.toarray() tot_fermions = numpy.dot( two_fermion_state.conjugate().T, numpy.dot(number_operator_matrix, two_fermion_state)) # checking the occupation number of site 2 and 3 number_operator_2 = bksf.number_operator(self.molecular_hamiltonian, 2) number_operator_3 = bksf.number_operator(self.molecular_hamiltonian, 3) number_operator_23 = number_operator_2 + number_operator_3 number_operator_23_sp_matrix = get_sparse_operator(number_operator_23) number_operator_23_matrix = number_operator_23_sp_matrix.toarray() tot_23_fermions = numpy.dot( two_fermion_state.conjugate().T, numpy.dot(number_operator_23_matrix, two_fermion_state)) self.assertTrue(2.0 - float(tot_fermions.real) < 1e-13) self.assertTrue(2.0 - float(tot_23_fermions.real) < 1e-13)
def test_apply_constraints(self): # Get norm of original operator. original_norm = 0. for term, coefficient in self.fermion_hamiltonian.terms.items(): if term != (): original_norm += abs(coefficient) # Get modified operator. modified_operator = apply_constraints(self.fermion_hamiltonian, self.n_fermions) modified_operator.compress() # Get norm of modified operator. modified_norm = 0. for term, coefficient in modified_operator.terms.items(): if term != (): modified_norm += abs(coefficient) self.assertTrue(modified_norm < original_norm) # Map both to sparse matrix under Jordan-Wigner. sparse_original = get_sparse_operator(self.fermion_hamiltonian) sparse_modified = get_sparse_operator(modified_operator) # Check spectra. sparse_original = jw_number_restrict_operator(sparse_original, self.n_fermions) sparse_modified = jw_number_restrict_operator(sparse_modified, self.n_fermions) original_spectrum = sparse_eigenspectrum(sparse_original) modified_spectrum = sparse_eigenspectrum(sparse_modified) spectral_deviation = numpy.amax( numpy.absolute(original_spectrum - modified_spectrum)) self.assertAlmostEqual(spectral_deviation, 0.) # Check expectation value. energy, wavefunction = get_ground_state(sparse_original) modified_energy = expectation(sparse_modified, wavefunction) self.assertAlmostEqual(modified_energy, energy)
def test_fourier_transform(self): for length in [2, 3]: grid = Grid(dimensions=1, scale=1.5, length=length) spinless_set = [True, False] geometry = [('H', (0.1,)), ('H', (0.5,))] for spinless in spinless_set: h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless, True) h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless, False) h_plane_wave_t = fourier_transform(h_plane_wave, grid, spinless) self.assertEqual(normal_ordered(h_plane_wave_t), normal_ordered(h_dual_basis)) # Verify that all 3 are Hermitian plane_wave_operator = get_sparse_operator(h_plane_wave) dual_operator = get_sparse_operator(h_dual_basis) plane_wave_t_operator = get_sparse_operator(h_plane_wave_t) self.assertTrue(is_hermitian(plane_wave_operator)) self.assertTrue(is_hermitian(dual_operator)) self.assertTrue(is_hermitian(plane_wave_t_operator))
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) # Confirm they are Hermitian momentum_kinetic_operator = get_sparse_operator(momentum_kinetic) self.assertTrue(is_hermitian(momentum_kinetic_operator)) position_kinetic_operator = get_sparse_operator(position_kinetic) self.assertTrue(is_hermitian(position_kinetic_operator)) # Confirm spectral match and hermiticity for length in [2, 3, 4]: grid = Grid(dimensions=1, length=length, scale=2.1) spinless = False momentum_kinetic = plane_wave_kinetic(grid, spinless) position_kinetic = dual_basis_kinetic(grid, spinless) # Confirm they are Hermitian momentum_kinetic_operator = get_sparse_operator(momentum_kinetic) self.assertTrue(is_hermitian(momentum_kinetic_operator)) position_kinetic_operator = get_sparse_operator(position_kinetic) self.assertTrue(is_hermitian(position_kinetic_operator)) # Diagonalize and confirm the same energy. jw_momentum = jordan_wigner(momentum_kinetic) jw_position = jordan_wigner(position_kinetic) momentum_spectrum = eigenspectrum(jw_momentum, 2 * length) position_spectrum = eigenspectrum(jw_position, 2 * length) # Confirm spectra are the same. difference = numpy.amax( numpy.absolute(momentum_spectrum - position_spectrum)) self.assertAlmostEqual(difference, 0.)
def test_constraint_matrix(self): # Randomly project operator with constraints. numpy.random.seed(8) constraints = constraint_matrix(self.n_orbitals, self.n_fermions) n_constraints, n_terms = constraints.shape self.assertEqual(1 + self.n_orbitals**2 + self.n_orbitals**4, n_terms) random_weights = numpy.random.randn(n_constraints) vectorized_operator = operator_to_vector(self.fermion_hamiltonian) modification_vector = constraints.transpose() * random_weights new_operator_vector = vectorized_operator + modification_vector modified_operator = vector_to_operator(new_operator_vector, self.n_orbitals) # Map both to sparse matrix under Jordan-Wigner. sparse_original = get_sparse_operator(self.fermion_hamiltonian) sparse_modified = get_sparse_operator(modified_operator) # Check expectation value. energy, wavefunction = get_ground_state(sparse_original) modified_energy = expectation(sparse_modified, wavefunction) self.assertAlmostEqual(modified_energy, energy)
def test_fermionic_hamiltonian_from_integrals(g, n_qubits): rg = RichardsonGaudin(g, n_qubits) #hc, hr1, hr2 = rg.hc, rg.hr1, rg.hr2 doci = rg constant = doci.constant reference_constant = 0 doci_qubit_op = doci.qubit_operator doci_mat = get_sparse_operator(doci_qubit_op).toarray() doci_eigvals = np.linalg.eigh(doci_mat)[0] tensors = doci.n_body_tensors one_body_tensors, two_body_tensors = tensors[(1, 0)], tensors[(1, 1, 0, 0)] fermion_op = get_fermion_operator( InteractionOperator(constant, one_body_tensors, 0.5 * two_body_tensors)) fermion_op = normal_ordered(fermion_op) fermion_mat = get_sparse_operator(fermion_op).toarray() fermion_eigvals = np.linalg.eigh(fermion_mat)[0] one_body_tensors2, two_body_tensors2 = rg.get_antisymmetrized_tensors() fermion_op2 = get_fermion_operator( InteractionOperator(reference_constant, one_body_tensors2, 0.5 * two_body_tensors2)) fermion_op2 = normal_ordered(fermion_op2) fermion_mat2 = get_sparse_operator(fermion_op2).toarray() fermion_eigvals2 = np.linalg.eigh(fermion_mat2)[0] for eigval in doci_eigvals: assert any(abs(fermion_eigvals - eigval) < 1e-6), "The DOCI spectrum should have \ been contained in the spectrum of the fermionic operator constructed via the \ DOCIHamiltonian class" for eigval in doci_eigvals: assert any(abs(fermion_eigvals2 - eigval) < 1e-6), "The DOCI spectrum should have \
def ansatz(q: qreg, x: List[float]): X(q[0]) # The goal of 'with decompose(..) as MAT' is to define a # the unitary matrix MAT within the scope of the # with statement. Here we use SciPy and Openfermion # to construct the X0Y1 - Y0X1 operator as a matrix. # Programmers must provide MAT as a numpy.matrix, # here todense() maps the sparse operator to a numpy.matrix. # Note that if your matrix is dependent on a kernel argument, # you must define it in the depends_on=[..] decompose arg. with decompose(q, kak) as u: from scipy.sparse.linalg import expm from openfermion.ops import QubitOperator from openfermion.linalg import get_sparse_operator qop = QubitOperator('X0 Y1') - QubitOperator('Y0 X1') qubit_sparse = get_sparse_operator(qop) u = expm(0.5j * x[0] * qubit_sparse).todense()
def test_prepare_gaussian_state_with_spin_symmetry(n_spatial_orbitals, conserves_particle_number, occupied_orbitals, initial_state, atol=1e-5): n_qubits = 2 * n_spatial_orbitals qubits = LineQubit.range(n_qubits) # Initialize a random quadratic Hamiltonian quad_ham = random_quadratic_hamiltonian(n_spatial_orbitals, conserves_particle_number, real=True, expand_spin=True, seed=639) # Reorder the Hamiltonian and get sparse matrix quad_ham = openfermion.get_quadratic_hamiltonian( openfermion.reorder(openfermion.get_fermion_operator(quad_ham), openfermion.up_then_down)) quad_ham_sparse = get_sparse_operator(quad_ham) # Compute the energy of the desired state energy = 0.0 for spin_sector in range(2): orbital_energies, _, _ = (quad_ham.diagonalizing_bogoliubov_transform( spin_sector=spin_sector)) energy += sum(orbital_energies[i] for i in occupied_orbitals[spin_sector]) energy += quad_ham.constant # Get the state using a circuit simulation circuit = cirq.Circuit( prepare_gaussian_state(qubits, quad_ham, occupied_orbitals, initial_state=initial_state)) if isinstance(initial_state, list): initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state) state = circuit.final_state_vector(initial_state=initial_state) # Check that the result is an eigenstate with the correct eigenvalue numpy.testing.assert_allclose(quad_ham_sparse.dot(state), energy * state, atol=atol)
def ham_sparse_matrix(q_system, excited_state=0): H_sparse_matrix = get_sparse_operator(q_system.jw_qubit_ham) if excited_state > 0: H_lower_state_terms = q_system.H_lower_state_terms assert H_lower_state_terms is not None assert len(H_lower_state_terms) >= excited_state for i in range(excited_state): term = H_lower_state_terms[i] state = term[1] statevector = QiskitSimBackend.statevector_from_ansatz( state.ansatz_elements, state.parameters, state.n_qubits, state.n_electrons, init_state_qasm=state.init_state_qasm) # add the outer product of the lower lying state to the Hamiltonian H_sparse_matrix += scipy.sparse.csr_matrix( term[0] * numpy.outer(statevector, statevector)) return H_sparse_matrix
def test_circuit_generation_state(): """ Determine if we rotate the Hartree-Fock state correctly """ simulator = cirq.Simulator() circuit = cirq.Circuit() qubits = cirq.LineQubit.range(4) circuit.append([ cirq.X(qubits[0]), cirq.X(qubits[1]), cirq.X(qubits[1]), cirq.X(qubits[2]), cirq.X(qubits[3]), cirq.X(qubits[3]) ]) # alpha-spins are first then beta spins wavefunction = numpy.zeros((2**4, 1), dtype=complex) wavefunction[10, 0] = 1.0 dim = 2 u_generator = numpy.random.random((dim, dim)) + 1j * numpy.random.random( (dim, dim)) u_generator = u_generator - numpy.conj(u_generator).T unitary = scipy.linalg.expm(u_generator) circuit.append(optimal_givens_decomposition(qubits[:2], unitary)) fermion_generator = QubitOperator(()) * 0.0 for i, j in product(range(dim), repeat=2): fermion_generator += jordan_wigner( FermionOperator(((i, 1), (j, 0)), u_generator[i, j])) test_unitary = scipy.linalg.expm( get_sparse_operator(fermion_generator, 4).toarray()) test_final_state = test_unitary.dot(wavefunction) cirq_wf = simulator.simulate(circuit).final_state_vector assert numpy.allclose(cirq_wf, test_final_state.flatten())
def test_prepare_gaussian_state(n_qubits, conserves_particle_number, occupied_orbitals, initial_state, atol=1e-5): qubits = LineQubit.range(n_qubits) # Initialize a random quadratic Hamiltonian quad_ham = random_quadratic_hamiltonian(n_qubits, conserves_particle_number, real=False) quad_ham_sparse = get_sparse_operator(quad_ham) # Compute the energy of the desired state if occupied_orbitals is None: energy = quad_ham.ground_energy() else: orbital_energies, _, constant = ( quad_ham.diagonalizing_bogoliubov_transform()) energy = sum(orbital_energies[i] for i in occupied_orbitals) + constant # Get the state using a circuit simulation circuit = cirq.Circuit( prepare_gaussian_state(qubits, quad_ham, occupied_orbitals, initial_state=initial_state)) if isinstance(initial_state, list): initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state) state = circuit.final_state_vector(initial_state=initial_state) # Check that the result is an eigenstate with the correct eigenvalue numpy.testing.assert_allclose(quad_ham_sparse.dot(state), energy * state, atol=atol)
def get_excitation_matrix(excitation_operator, n_qubits, parameter=1): assert parameter.imag == 0 # ? qubit_operator_matrix = get_sparse_operator(excitation_operator, n_qubits) return scipy.sparse.linalg.expm(parameter * qubit_operator_matrix)
def ansatz_gradient(var_parameters, ansatz, q_system, cache=None, init_state_qasm=None, excited_state=0): assert len(ansatz) == len(var_parameters) ansatz_statevector = QiskitSimBackend.statevector_from_ansatz( ansatz, var_parameters, q_system.n_orbitals, q_system.n_electrons, init_state_qasm=init_state_qasm) ansatz_sparse_statevector = scipy.sparse.csr_matrix(ansatz_statevector) H_sparse_matrix = QiskitSimBackend.ham_sparse_matrix( q_system, excited_state=excited_state) phi = ansatz_sparse_statevector.transpose().conj() psi = H_sparse_matrix.dot(phi) ansatz_grad = [] for i in range(len(ansatz))[::-1]: excitations_generators = ansatz[i].excitations_generators excitations_generators_matrices = [] for term in excitations_generators: excitations_generators_matrices.append( get_sparse_operator(term, n_qubits=q_system.n_qubits)) if len(excitations_generators_matrices) == 1: grad_i = 2 * (psi.transpose().conj().dot( excitations_generators_matrices[0]).dot(phi)).todense()[0, 0] ansatz_grad.append(grad_i.real) psi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[0], psi) phi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[0], phi) else: # TODO test properly assert len(excitations_generators_matrices) == 2 psi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[1], psi) phi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[1], phi) grad_i = 2 * (psi.transpose().conj().dot( excitations_generators_matrices[0] + excitations_generators_matrices[1]).dot(phi)).todense()[0, 0] ansatz_grad.append(grad_i.real) psi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[0], psi) phi = scipy.sparse.linalg.expm_multiply( -var_parameters[i] * excitations_generators_matrices[0], phi) ansatz_grad = ansatz_grad[::-1] # print(ansatz_grad) return numpy.array(ansatz_grad)