Path: blob/main/chemistry-simulations/aux_files/krylov/qchem/uccsd_vqe.py
583 views
import cudaq1from aux_files.krylov.qchem.uccsd import get_uccsd_op, uccsd_circuit2from aux_files.krylov.qchem.uccsd import uccsd_circuit_double, uccsd_circuit_single34import numpy as np5from scipy.optimize import minimize67cudaq.set_target("nvidia", option='fp64')8910def uccsd_circuit_vqe(spin_mult,11only_singles,12only_doubles,13qubits_num,14electron_count,15optimize,16theta,17hamiltonian,18method='BFGS',19vqe_tol=1e-3,20verbose=False):21"""22Generate the UCCSD circuit for VQE.2324Parameters:25- spin_`mult`: Spin multiplicity of the system.26- only_singles: If True, only single excitations are included.27- only_doubles: If True, only double excitations are included.28- qubits_`num`: Number of qubits in the system.29- electron_count: Number of electrons in the system.30- theta: Initial parameters for the circuit.31- hamiltonian: Hamiltonian of the system.32"""3334# Get the UCCSD pool35if not only_singles and not only_doubles:36word_single, word_double, coef_single, coef_double = get_uccsd_op(37electron_count,38qubits_num,39spin_mult=0,40only_singles=False,41only_doubles=False)42if verbose:43print(f"word_single: {word_single}")44print(f"word_double: {word_double}")45print(f"coef_single: {coef_single}")46print(f"coef_double: {coef_double}")4748elif only_singles and not only_doubles:49word_single, coef_single = get_uccsd_op(electron_count,50qubits_num,51spin_mult=0,52only_singles=True,53only_doubles=False)5455if verbose:56print(f"word_single: {word_single}")57print(f"coef_single: {coef_single}")5859elif only_doubles and not only_singles:60word_double, coef_double = get_uccsd_op(electron_count,61qubits_num,62spin_mult=0,63only_singles=False,64only_doubles=True)6566if verbose:67print(f"word_double: {word_double}")68print(f"coef_double: {coef_double}")69else:70raise ValueError("Invalid option for only_singles and only_doubles")7172# Get the UCCSD circuit (singles and doubles excitation are included)73@cudaq.kernel74def uccsd_kernel(qubits_num: int, electron_count: int, theta: list[float],75word_single: list[cudaq.pauli_word],76word_double: list[cudaq.pauli_word],77coef_single: list[float], coef_double: list[float]):78"""79UCCSD kernel80"""81# `Prepare the statefrom qchem.uccsd import get_uccsd_op, uccsd_circuit, uccsd_parameter_size`8283qubits = cudaq.qvector(qubits_num)8485# Initialize the qubits86for i in range(electron_count):87x(qubits[i])8889# Apply the UCCSD circuit90uccsd_circuit(qubits, theta, word_single, coef_single, word_double,91coef_double)9293# Get the UCCSD circuit (only doubles excitations are included)94@cudaq.kernel95def uccsd_double_kernel(qubits_num: int, electron_count: int,96theta: list[float],97word_double: list[cudaq.pauli_word],98coef_double: list[float]):99"""100UCCSD kernel101"""102# Prepare the state103qubits = cudaq.qvector(qubits_num)104105# Initialize the qubits106for i in range(electron_count):107x(qubits[i])108109# Apply the UCCSD circuit110uccsd_circuit_double(qubits, theta, word_double, coef_double)111112# Get the UCCSD circuit (only singles excitations are included)113@cudaq.kernel114def uccsd_single_kernel(qubits_num: int, electron_count: int,115theta: list[float],116word_single: list[cudaq.pauli_word],117coef_single: list[float]):118"""119UCCSD kernel120"""121# Prepare the state122qubits = cudaq.qvector(qubits_num)123124# Initialize the qubits125for i in range(electron_count):126x(qubits[i])127128# Apply the UCCSD circuit129uccsd_circuit_single(qubits, theta, word_single, coef_single)130131def cost(theta):132133theta = theta.tolist()134135if not only_singles and not only_doubles:136energy = cudaq.observe(uccsd_kernel, hamiltonian, qubits_num,137electron_count, theta, word_single,138word_double, coef_single,139coef_double).expectation()140141142elif only_singles and not only_doubles:143energy = cudaq.observe(uccsd_single_kernel, hamiltonian, qubits_num,144electron_count, theta, word_single,145coef_single).expectation()146147elif only_doubles and not only_singles:148energy = cudaq.observe(uccsd_double_kernel, hamiltonian, qubits_num,149electron_count, theta, word_double,150coef_double).expectation()151152else:153raise ValueError("Invalid option for only_singles and only_doubles")154155return energy156157if optimize:158if method == 'L-BFGS-B':159result_vqe = minimize(cost,160theta,161method='L-BFGS-B',162jac='3-point',163tol=vqe_tol)164print('Optimizer exited successfully: ',165result_vqe.success,166flush=True)167elif method == 'BFGS':168result_vqe = minimize(cost,169theta,170method='BFGS',171jac='3-point',172options={'gtol': 1e-5})173print('Optimizer exited successfully: ',174result_vqe.success,175flush=True)176elif method == 'COBYLA':177result_vqe = minimize(cost,178theta,179method='COBYLA',180options={181'rhobeg': 1.0,182'maxiter': 20000,183'disp': False,184'tol': vqe_tol185})186else:187raise ValueError(188"Invalid optimization method. Use 'L-BFGS-B', 'BFGS', or 'COBYLA'."189)190191total_energy = result_vqe.fun192193if verbose:194print(f"Total energy: {total_energy:.10f} Hartree")195# Print the optimized parameters: first n are singles, then doubles.196if verbose:197print(f"optimized parameters: {result_vqe.x}")198199return (result_vqe.fun, result_vqe.x, result_vqe.success, np.array(cudaq.get_state(uccsd_kernel, qubits_num,200electron_count,result_vqe.x, word_single,201word_double, coef_single,202coef_double)))203204else:205total_energy = cudaq.observe(uccsd_kernel, hamiltonian, qubits_num,206electron_count, theta, word_single,207word_double, coef_single,208coef_double).expectation()209if verbose:210print(f"Total energy: {total_energy:.10f} Hartree")211212print(np.array(cudaq.get_state(uccsd_kernel, qubits_num,213electron_count,theta, word_single,214word_double, coef_single,215coef_double)))216217print(cudaq.get_state(uccsd_kernel, qubits_num,218electron_count,theta, word_single,219word_double, coef_single,220coef_double))221222return (total_energy, theta, True, np.array(cudaq.get_state(uccsd_kernel, qubits_num,223electron_count,theta, word_single,224word_double, coef_single,225coef_double)) )226227