def make_h3_2_5() -> Tuple[RestrictedHartreeFockObjective, of.MolecularData, np.ndarray, np.ndarray, np.ndarray]: # load the molecule from moelcular data h3_2_5_path = os.path.join( hfvqe.__path__[0], 'molecular_data/hydrogen_chains/h_3_p_sto-3g/bond_distance_2.5') molfile = os.path.join(h3_2_5_path, 'H3_plus_sto-3g_singlet_linear_r-2.5.hdf5') molecule = of.MolecularData(filename=molfile) molecule.load() S = np.load(os.path.join(h3_2_5_path, 'overlap.npy')) Hcore = np.load(os.path.join(h3_2_5_path, 'h_core.npy')) TEI = np.load(os.path.join(h3_2_5_path, 'tei.npy')) _, X = sp.linalg.eigh(Hcore, S) obi = of.general_basis_change(Hcore, X, (1, 0)) tbi = np.einsum('psqr', of.general_basis_change(TEI, X, (1, 0, 1, 0))) molecular_hamiltonian = generate_hamiltonian(obi, tbi, molecule.nuclear_repulsion) rhf_objective = RestrictedHartreeFockObjective(molecular_hamiltonian, molecule.n_electrons) scipy_result = rhf_minimization(rhf_objective) return rhf_objective, molecule, scipy_result.x, obi, tbi
def make_h3_2_5(molecular_data_directory=None) \ -> Tuple[RestrictedHartreeFockObjective, of.MolecularData, np.ndarray, np.ndarray, np.ndarray]: if molecular_data_directory is None: molecular_data_directory = _MOLECULAR_DATA_DIRECTORY h3_2_5_path = f'{molecular_data_directory}/hydrogen_chains/h_3_p_sto-3g/bond_distance_2.5' molfile = f'{h3_2_5_path}/H3_plus_sto-3g_singlet_linear_r-2.5.hdf5' molecule = of.MolecularData(filename=molfile) molecule.load() S = np.load(os.path.join(h3_2_5_path, 'overlap.npy')) Hcore = np.load(os.path.join(h3_2_5_path, 'h_core.npy')) TEI = np.load(os.path.join(h3_2_5_path, 'tei.npy')) _, X = sp.linalg.eigh(Hcore, S) obi = of.general_basis_change(Hcore, X, (1, 0)) tbi = np.einsum('psqr', of.general_basis_change(TEI, X, (1, 0, 1, 0))) molecular_hamiltonian = generate_hamiltonian(obi, tbi, molecule.nuclear_repulsion) rhf_objective = RestrictedHartreeFockObjective(molecular_hamiltonian, molecule.n_electrons) scipy_result = rhf_minimization(rhf_objective) return rhf_objective, molecule, scipy_result.x, obi, tbi
def make_rhf_objective(molecule: of.MolecularData): S, Hcore, TEI = get_ao_integrals(molecule) _, X = sp.linalg.eigh(Hcore, S) obi = of.general_basis_change(Hcore, X, (1, 0)) tbi = np.einsum('psqr', of.general_basis_change(TEI, X, (1, 0, 1, 0))) molecular_hamiltonian = generate_hamiltonian(obi, tbi, molecule.nuclear_repulsion) rhf_objective = RestrictedHartreeFockObjective(molecular_hamiltonian, molecule.n_electrons) return rhf_objective, S, Hcore, TEI, obi, tbi
def make_rhf_objective(molecule): # coverage: ignore S, Hcore, TEI = get_ao_integrals(molecule) _, X = scipy.linalg.eigh(Hcore, S) molecular_hamiltonian = generate_hamiltonian( general_basis_change(Hcore, X, (1, 0)), numpy.einsum('psqr', general_basis_change(TEI, X, (1, 0, 1, 0)), molecule.nuclear_repulsion)) rhf_objective = RestrictedHartreeFockObjective(molecular_hamiltonian, molecule.n_electrons) return rhf_objective, S, Hcore, TEI
def moving_frame_augmented_hessian_optimizer( rhf_objective: RestrictedHartreeFockObjective, initial_parameters: np.ndarray, opdm_aa_measurement_func: Callable, max_iter: Optional[int] = 15, rtol: Optional[float] = 0.2E-2, delta: Optional[float] = 0.03, verbose: Optional[bool] = True, hessian_update: Optional[bool] = 'diagonal'): # testpragma: no cover # coverage: ignore """The moving frame optimizer. Determine an optimal basis rotation by continuously updating the coordinate system and asking if stationarity is achieved. Args: rhf_objective: recirq.hfvqe.RestrictedHartreeFockObjective initial_parameters: parameters to start the optimization opdm_aa_measurement_func: callable functioon that takes the parameter vector and returns the opdm max_iter: maximum number of iterations to take rtol: Terminate the optimization with the norm of the update angles falls below this threshold verbose: Allow printing of intermediate optimization information hessian_update: Optional argument if diagonal or full Hessian is used """ if delta > 1 or delta < 0: raise ValueError("Delta must be in the domain [0, 1]") if hessian_update not in ['diagonal', 'energy']: raise ValueError("hessian_update parameter not valid.") res = OptimizeResult() res.fr_vals = [] res.opdms = [] res.x_iters = [] res.func_vals = [] res.f = None res.iter_times = [] fr_vals = initial_parameters current_unitary = np.eye(rhf_objective.nocc + rhf_objective.nvirt) break_at_count = max_iter current_count = 0 energies = [] fval_norms = [] # for debugging opdm_initial = np.diag([1] * rhf_objective.nocc + [0] * rhf_objective.nvirt) start_time = time.time() while current_count < break_at_count: # Iterate of algorithm has a unitary and parameters # first step is to generate new unitary u_new = group_action(old_unitary=current_unitary, new_parameters=fr_vals, occ=rhf_objective.occ, virt=rhf_objective.virt) # get initial opdm from starting parameters opdm = opdm_aa_measurement_func(u_new.copy()) # opdm = u_new @ opdm_initial @ u_new.conj().T # Calculate energy, residual, and hessian terms rdms: InteractionRDM = rhf_objective.rdms_from_opdm_aa(opdm) current_energy: float = rdms.expectation( rhf_objective.hamiltonian).real energies.append(current_energy) res.x_iters.append(u_new) res.func_vals.append(current_energy) res.fr_vals.append(fr_vals) res.opdms.append(opdm) res.iter_times.append(time.time() - start_time) rot_gens = non_redundant_rotation_generators(rhf_objective) dvec, hmat = get_dvec_hmat( rotation_generators=rot_gens, rhf_objective=rhf_objective, rdms=rdms, diagonal_hessian=True if hessian_update == 'diagonal' else False) # talk if talking is allowed if verbose: print("\nITERATION NUMBER : ", current_count) print("\n unitary") print(current_unitary) test_opdm_aa = u_new @ opdm_initial @ u_new.conj().T true_energy = rhf_objective.energy_from_opdm(test_opdm_aa) print("Current Energy: ", current_energy) print("true energy ", true_energy) print("dvec") print(list(zip(dvec, rot_gens))) # build augmented Hessian dvec = dvec.reshape((-1, 1)) aug_hess = np.hstack((np.array([[0]]), dvec.conj().T)) aug_hess = np.vstack((aug_hess, np.hstack((dvec, hmat)))) w, v = np.linalg.eig(aug_hess) sort_idx = np.argsort(w) w = w[sort_idx] v = v[:, sort_idx] new_fr_vals = v[1:, [0]].flatten() / v[0, 0] assert new_fr_vals.shape[0] == initial_parameters.shape[0] assert np.isclose(w[0], dvec.T @ new_fr_vals) # Qiming's algorithm for no learning rate rescaling if np.max(abs(new_fr_vals)) >= delta: new_fr_vals = delta * new_fr_vals / np.max(abs(new_fr_vals)) # keep track of the norm fval_norms.append(np.linalg.norm(new_fr_vals)) # allow a stopping condition if verbose: print("New fr values norm") print(np.linalg.norm(new_fr_vals)) if np.linalg.norm(new_fr_vals) < rtol: if verbose: print("Finished Optimization") break # assign new values to the things being evaluated next iteration fr_vals = new_fr_vals.copy() current_unitary = u_new.copy() current_count += 1 return res