def test_prepare_gaussian_state(n_qubits, conserves_particle_number, occupied_orbitals, initial_state, atol=1e-5): qubits = LineQubit.range(n_qubits) if isinstance(initial_state, list): initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state) # 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.from_ops( prepare_gaussian_state( qubits, quad_ham, occupied_orbitals, initial_state=initial_state)) state = circuit.apply_unitary_effect_to_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 kevin_hubbard_cirq(self): # Create Hubbard model Hamiltonian # -------------------------------- x_dim = 3 y_dim = 2 n_sites = x_dim * y_dim n_modes = 2 * n_sites tunneling = 1.0 coulomb = 4.0 hubbard_model = of.fermi_hubbard(x_dim, y_dim, tunneling, coulomb) # Reorder indices hubbard_model = of.reorder(hubbard_model, of.up_then_down) # Convert to DiagonalCoulombHamiltonian hubbard_hamiltonian = of.get_diagonal_coulomb_hamiltonian( hubbard_model) # Create qubits qubits = cirq.LineQubit.range(n_modes) # State preparation circuit for eigenstate of one-body term # --------------------------------------------------------- # Set the pseudo-particle orbitals to fill up_orbitals = range(n_sites // 2) down_orbitals = range(n_sites // 2) # Create the circuit hubbard_state_preparation_circuit = cirq.Circuit.from_ops( ofc.prepare_gaussian_state( qubits, of.QuadraticHamiltonian(hubbard_hamiltonian.one_body), occupied_orbitals=(up_orbitals, down_orbitals)), strategy=cirq.InsertStrategy.EARLIEST) # Trotter simulation circuit # -------------------------- n_steps = 10 order = 0 hubbard_simulation_circuit = cirq.Circuit.from_ops( ofc.simulate_trotter(qubits, hubbard_hamiltonian, time=1.0, n_steps=n_steps, order=order, algorithm=ofc.trotter.LINEAR_SWAP_NETWORK), strategy=cirq.InsertStrategy.EARLIEST) t0 = time.time() self.kevin_optimize_circuit(hubbard_state_preparation_circuit) self.kevin_optimize_circuit(hubbard_simulation_circuit) t1 = time.time() # print('Optimizing circuits took {} seconds'.format(t1 - t0)) # print(hubbard_state_preparation_circuit.to_text_diagram(transpose=True)) return hubbard_state_preparation_circuit, hubbard_simulation_circuit
def test_trotter_ansatzes_default_initial_params_iterations_1( ansatz_factory, trotter_algorithm, order, hamiltonian, atol): """Check that a Trotter ansatz with one iteration and default parameters is consistent with time evolution with one Trotter step.""" ansatz = ansatz_factory(hamiltonian, iterations=1) objective = HamiltonianObjective(hamiltonian) qubits = ansatz.qubits if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): one_body = hamiltonian.one_body elif isinstance(hamiltonian, openfermion.InteractionOperator): one_body = hamiltonian.one_body_tensor preparation_circuit = cirq.Circuit.from_ops( prepare_gaussian_state(qubits, openfermion.QuadraticHamiltonian(one_body), occupied_orbitals=range(len(qubits) // 2))) # Compute value using ansatz circuit and objective circuit = (preparation_circuit + ansatz.circuit).with_parameters_resolved_by( ansatz.param_resolver(ansatz.default_initial_params())) result = circuit.apply_unitary_effect_to_state( qubit_order=ansatz.qubit_permutation(qubits)) obj_val = objective.value(result) # Compute value using study study = VariationalStudy('study', ansatz, objective, preparation_circuit=preparation_circuit) study_val = study.value_of(ansatz.default_initial_params()) # Compute value by simulating time evolution if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): half_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.5 * hamiltonian.two_body) elif isinstance(hamiltonian, openfermion.InteractionOperator): half_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.5 * hamiltonian.two_body_tensor) simulation_circuit = cirq.Circuit.from_ops( simulate_trotter(qubits, half_way_hamiltonian, time=ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm)) final_state = (preparation_circuit + simulation_circuit).apply_unitary_effect_to_state() correct_val = openfermion.expectation(objective._hamiltonian_linear_op, final_state).real numpy.testing.assert_allclose(obj_val, study_val, atol=atol) numpy.testing.assert_allclose(obj_val, correct_val, atol=atol)
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.from_ops( 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.apply_unitary_effect_to_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 test_trotter_ansatzes_evaluate_order_2(ansatz_factory, trotter_algorithm, hamiltonian, atol): """Check that a Trotter ansatz with two iterations and default parameters is consistent with time evolution with two Trotter steps.""" ansatz = ansatz_factory(hamiltonian, iterations=2) qubits = ansatz.qubits preparation_circuit = cirq.Circuit.from_ops( prepare_gaussian_state(qubits, openfermion.QuadraticHamiltonian( hamiltonian.one_body), occupied_orbitals=range(len(qubits) // 2))) study = HamiltonianVariationalStudy( 'study', ansatz, hamiltonian, preparation_circuit=preparation_circuit) simulator = cirq.google.XmonSimulator() # Compute value using ansatz val = study.evaluate(study.default_initial_params()) # Compute value by simulating time evolution quarter_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.25 * hamiltonian.two_body) three_quarters_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.75 * hamiltonian.two_body) simulation_circuit = cirq.Circuit.from_ops( simulate_trotter(qubits, quarter_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=1, algorithm=trotter_algorithm), simulate_trotter(qubits, three_quarters_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=1, algorithm=trotter_algorithm)) circuit = preparation_circuit + simulation_circuit result = simulator.simulate(circuit) final_state = result.final_state correct_val = openfermion.expectation(study._hamiltonian_linear_op, final_state).real numpy.testing.assert_allclose(val, correct_val, atol=atol)
def kevin_lih_cirq(self): x_dim = 3 y_dim = 2 n_sites = x_dim * y_dim n_modes = 2 * n_sites # Create LiH Hamiltonian # ---------------------- bond_length = 1.45 geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., bond_length))] n_active_electrons = 4 n_active_orbitals = 4 lih_hamiltonian = of.load_molecular_hamiltonian( geometry, 'sto-3g', 1, format(bond_length), n_active_electrons, n_active_orbitals) # Generate qubits n_qubits = of.count_qubits(lih_hamiltonian) qubits = cirq.LineQubit.range(n_qubits) # State preparation circuit for eigenstate of one-body term # --------------------------------------------------------- # Set the pseudo-particle orbitals to fill occupied_orbitals = range(n_qubits // 2) # State preparation circuit for eigenstate of one-body term # --------------------------------------------------------- # Set the pseudo-particle orbitals to fill up_orbitals = range(n_sites // 2) down_orbitals = range(n_sites // 2) # Create the circuit lih_state_preparation_circuit = cirq.Circuit.from_ops( ofc.prepare_gaussian_state( qubits, of.QuadraticHamiltonian(lih_hamiltonian.one_body_tensor), occupied_orbitals=(up_orbitals, down_orbitals)), strategy=cirq.InsertStrategy.EARLIEST) # Trotter simulation circuit # -------------------------- n_steps = 10 order = 0 lih_simulation_circuit = cirq.Circuit.from_ops( ofc.simulate_trotter(qubits, lih_hamiltonian, time=1.0, n_steps=n_steps, order=order, algorithm=ofc.trotter.LOW_RANK), strategy=cirq.InsertStrategy.EARLIEST) t0 = time.time() self.kevin_optimize_circuit(lih_state_preparation_circuit) self.kevin_optimize_circuit(lih_simulation_circuit) t1 = time.time() # print('Optimizing circuits took {} seconds'.format(t1 - t0)) # print(lih_state_preparation_circuit.to_text_diagram(transpose=True)) return lih_state_preparation_circuit, lih_simulation_circuit
# Define the objective function objective = openfermioncirq.HamiltonianObjective(hamiltonian) # Create a swap network Trotter ansatz. iterations = 1 # This is the number of Trotter steps to use in the ansatz. ansatz = openfermioncirq.SwapNetworkTrotterAnsatz(hamiltonian, iterations=iterations) print('Created a variational ansatz with the following circuit:') print(ansatz.circuit.to_text_diagram(transpose=True)) # Use preparation circuit for mean-field state import cirq preparation_circuit = cirq.Circuit( openfermioncirq.prepare_gaussian_state( ansatz.qubits, openfermion.QuadraticHamiltonian(hamiltonian.one_body), occupied_orbitals=range(n_electrons))) kc_simulator = cirq.KnowledgeCompilationSimulator(preparation_circuit + ansatz.circuit, initial_state=0) # Create a Hamiltonian variational study study = openfermioncirq.VariationalStudy( 'jellium_study', ansatz, objective, preparation_circuit=preparation_circuit) print("Created a variational study with {} qubits and {} parameters".format( len(study.ansatz.qubits), study.num_params))
def get_qubit_hamiltonian(g, basis, charge=0, spin=1, qubit_transf='jw'): ## Create OpenFermion molecule #mol = gto.Mole() #mol.atom = g #mol.basis = basis #mol.spin = spin #mol.charge = charge #mol.symmetry = False ##mol.max_memory = 1024 #mol.build() multiplicity = spin + 1 # spin here is 2S ? mol = MolecularData(g, basis, multiplicity, charge) #mol.load() # Convert to PySCF molecule and run SCF print("Running run_pyscf...") print(f"Time: {time()}") print("=" * 20) mol = run_pyscf(mol) # Freeze some orbitals? occupied_indices = None active_indices = None #import pdb; pdb.set_trace() # Try: occupied_indices = range(183) active_indices = range(15) # when it stops lagging # Get Hamiltonian print("Running get_molecular_hamiltonian...") print(f"Time: {time()}") print("=" * 20) ham = mol.get_molecular_hamiltonian(occupied_indices=occupied_indices, active_indices=active_indices) print("Running get_fermion_operator...") print(f"Time: {time()}") print("=" * 20) hamf = get_fermion_operator(ham) print(f"Running {qubit_transf}...") print(f"Time: {time()}") print("=" * 20) if qubit_transf == 'bk': hamq = bravyi_kitaev(hamf) elif qubit_transf == 'jw': hamq = jordan_wigner(hamf) else: raise (ValueError(qubit_transf, 'Unknown transformation specified')) # Adapted from 10.5281/zenodo.2880550 hamd = openfermion.get_diagonal_coulomb_hamiltonian( hamf, ignore_incompatible_terms=True) nqubits = openfermion.count_qubits(hamd) ansatz = openfermioncirq.SwapNetworkTrotterAnsatz(hamd, iterations=3) print(ansatz.circuit.to_text_diagram(transpose=True)) nelectrons = 8 # TODO: CHECK WHICH ORBITALS ARE SAMPLED!! prep_circuit = cirq.Circuit( openfermioncirq.prepare_gaussian_state( ansatz.qubits, openfermion.QuadraticHamiltonian( hamd.one_body))) # TODO: Verify this line objective = openfermioncirq.HamiltonianObjective(hamd) study = openfermioncirq.VariationalStudy(name='hamil', ansatz=ansatz, objective=objective, preparation_circuit=prep_circuit) print("The energy of the default initial guess is {}.".format( study.value_of(ansatz.default_initial_params()))) print() alg = openfermioncirq.optimization.ScipyOptimizationAlgorithm( kwargs={'method': 'COBYLA'}, uses_bounds=False) opt_params = openfermioncirq.optimization.OptimizationParams( algorith=alg, initial_guess=ansat.default_initial_params()) result = study.optimize(opt_param) print("Optimized energy: {}".format(result.optimal_value)) print()
def test_trotter_ansatzes_default_initial_params_iterations_2( ansatz, trotter_algorithm, order, hamiltonian, atol): """Check that a Trotter ansatz with two iterations and default parameters is consistent with time evolution with two Trotter steps.""" objective = HamiltonianObjective(hamiltonian) qubits = ansatz.qubits if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): one_body = hamiltonian.one_body elif isinstance(hamiltonian, openfermion.InteractionOperator): one_body = hamiltonian.one_body_tensor if isinstance(ansatz, SwapNetworkTrotterHubbardAnsatz): occupied_orbitals = (range(len(qubits) // 4), range(len(qubits) // 4)) else: occupied_orbitals = range(len(qubits) // 2) preparation_circuit = cirq.Circuit( prepare_gaussian_state(qubits, openfermion.QuadraticHamiltonian(one_body), occupied_orbitals=occupied_orbitals)) # Compute value using ansatz circuit and objective circuit = cirq.resolve_parameters( preparation_circuit + ansatz.circuit, ansatz.param_resolver(ansatz.default_initial_params())) result = circuit.final_wavefunction( qubit_order=ansatz.qubit_permutation(qubits)) obj_val = objective.value(result) # Compute value using study study = VariationalStudy('study', ansatz, objective, preparation_circuit=preparation_circuit) study_val = study.value_of(ansatz.default_initial_params()) # Compute value by simulating time evolution if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): quarter_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.25 * hamiltonian.two_body) three_quarters_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.75 * hamiltonian.two_body) elif isinstance(hamiltonian, openfermion.InteractionOperator): quarter_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.25 * hamiltonian.two_body_tensor) three_quarters_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.75 * hamiltonian.two_body_tensor) simulation_circuit = cirq.Circuit( simulate_trotter(qubits, quarter_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm), simulate_trotter(qubits, three_quarters_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm)) final_state = (preparation_circuit + simulation_circuit).final_wavefunction() correct_val = openfermion.expectation(objective._hamiltonian_linear_op, final_state).real numpy.testing.assert_allclose(obj_val, study_val, atol=atol) numpy.testing.assert_allclose(obj_val, correct_val, atol=atol)