def load_and_encode(file_name: str, problem_description_index: int = 0, initial_state_label: str = None) -> JWEncodedData: """Wrapper function for loading and encoding Broombridge file into JWEncodedData-compatible format. :param file_name: Broombridge file name :type file_name: str :param problem_description_index: Index of problem description to use, defaults to 0 :type problem_description_index: int, optional :param initial_state_label: Label of initial state to use, defaults to first available label :type initial_state_label: str, optional """ broombridge_data = load_broombridge(file_name) problem = broombridge_data.problem_description[problem_description_index] if initial_state_label is None: # Pick first in list initial_state_label = problem.initial_state_suggestions[0].get("Label") _log.info(f"Using initial state label: {initial_state_label}") input_state = load_input_state(file_name, initial_state_label) ferm_hamiltonian = problem.load_fermion_hamiltonian() (num_qubits, hamiltonian_term_list, input_state_terms, energy_offset) = encode(ferm_hamiltonian, input_state) return (num_qubits, hamiltonian_term_list, input_state_terms, energy_offset)
def load_jw_encoded_data(filename: str): broombridge_data = load_broombridge(filename) problem_description = broombridge_data.problem_description[0] ferm_hamiltonian = problem_description.load_fermion_hamiltonian() input_state = load_input_state(filename, "UCCSD |G>") jw_encoded = encode(ferm_hamiltonian, input_state) return jw_encoded
def test_jw_encode(): """ Checks that we can encode a hamiltonian + input state """ broombridge = qsharp.chemistry.load_broombridge("broombridge.yaml") fh1 = broombridge.problem_description[0].load_fermion_hamiltonian() is1 = broombridge.problem_description[0].load_input_state() jw = encode(fh1, is1) assert(len(jw) == 4)
def __init__(self, ansatz, molecule, mean_field=None, backend_options=None): """Initialize the settings for simulation. If the mean field is not provided it is automatically calculated. Args: ansatz (OpenFermionParametricSolver.Ansatze): Ansatz for the quantum solver. molecule (pyscf.gto.Mole): The molecule to simulate. mean_field (pyscf.scf.RHF): The mean field of the molecule. backend_options (dict): Extra parameters that control the behaviour of the solver. """ # Import python packages for Microsoft Python interops import qsharp import qsharp.chemistry as qsharpchem assert(isinstance(ansatz, MicrosoftQSharpParametricSolver.Ansatze)) self.ansatz = ansatz self.verbose = False # Initialize the number of samples to be used by the MicrosoftQSharp backend self.n_samples = 1e18 # Initialize the amplitudes (parameters to be optimized) self.optimized_amplitudes = [] # Obtain fragment info with PySCF # ----------------------------------------- # Compute mean-field if not provided. Check that it has converged if not mean_field: mean_field = scf.RHF(molecule) mean_field.verbose = 0 mean_field.scf() if (mean_field.converged == False): orb_temp = mean_field.mo_coeff occ_temp = mean_field.mo_occ nr = scf.newton(mean_field) energy = nr.kernel(orb_temp, occ_temp) mean_field = nr if not mean_field.converged: warnings.warn("MicrosoftQSharpParametricSolver simulating with mean field not converged.", RuntimeWarning) self.molecule = molecule self.mean_field = mean_field self.n_orbitals = len(mean_field.mo_energy) self.n_spin_orbitals = 2 * self.n_orbitals self.n_electrons = molecule.nelectron nuclear_repulsion = mean_field.energy_nuc() # Compute and set values of electronic integrals # ---------------------------------------------- # Get data-structure to store problem description fd, path = tempfile.mkstemp(suffix='.yaml') try: # Write the dummp_0.2.yaml file to a temporary file with os.fdopen(fd, 'w') as tmp: tmp.write(_dummy_0_2_yaml) molecular_data = qsharpchem.load_broombridge(path) # Compute one and two-electron integrals, store them in the Microsoft data-structure integrals_one, integrals_two = compute_integrals_fragment(molecule, mean_field) molecular_data.problem_description[0].hamiltonian['OneElectronIntegrals']['Values'] = integrals_one molecular_data.problem_description[0].hamiltonian['TwoElectronIntegrals']['Values'] = integrals_two molecular_data.problem_description[0].coulomb_repulsion['Value'] = nuclear_repulsion # Compute and set values of UCCSD operators # ----------------------------------------- # Generate UCCSD one- and two-body operators n_amplitudes = count_amplitudes(self.n_spin_orbitals, self.n_electrons) self.amplitude_dimension = n_amplitudes amplitudes = 0.01 * np.ones((n_amplitudes), dtype=np.float64) self.preferred_var_params = amplitudes ref,t = compute_cluster_operator(self.n_spin_orbitals, self.n_electrons, amplitudes) # Load a dummy inputstate object from the dummy Broombridge file, and set its values self.inputstate = qsharpchem.load_input_state(path, "UCCSD |G>") if self.verbose: print("inputstate energy :\n", self.inputstate.Energy) print("inputstate mcfdata :\n", self.inputstate.MCFData) print("inputstate method :\n", self.inputstate.Method) print("inputstate scfdata :\n", self.inputstate.SCFData) print("inputstate uccdata :\n", self.inputstate.UCCData, "\n\n\n") self.inputstate.UCCData['Reference'] = ref self.inputstate.UCCData['Excitations'] = t if self.verbose: print("inputstate :\n", self.inputstate.UCCData) print("------------\n") # Generate Fermionic and then qubit Hamiltonians # ---------------------------------------------- # C# Chemistry library : Compute fermionic Hamiltonian self.ferm_hamiltonian = molecular_data.problem_description[0].load_fermion_hamiltonian() if self.verbose: print("ferm_hamiltonian:\n", self.ferm_hamiltonian.terms) print("------------\n") # C# Chemistry library : Compute the Pauli Hamiltonian using the Jordan-Wigner transform self.jw_hamiltonian = qsharpchem.encode(self.ferm_hamiltonian, self.inputstate) if self.verbose: print("jw_hamiltonian ::", self.jw_hamiltonian) print("------------\n") # Retrieve energy offset and number of qubits self.n_qubits = self.jw_hamiltonian[0] self.energy_offset = self.jw_hamiltonian[3] finally: # Cleanup the temp file os.remove(path)
def get_rdm(self): """Obtain the RDMs from the optimized amplitudes. Obtain the RDMs from the optimized amplitudes by using the same function for energy evaluation. The RDMs are computed by using each fermionic Hamiltonian term, transforming them and computing the elements one-by-one. Note that the Hamiltonian coefficients will not be multiplied as in the energy evaluation. The first element of the Hamiltonian is the nuclear repulsion energy term, not the Hamiltonian term. Returns: (numpy.array, numpy.array): One & two-particle RDMs (rdm1_np & rdm2_np, float64). """ import qsharp import qsharp.chemistry as qsharpchem amplitudes = self.optimized_amplitudes one_rdm = np.zeros((self.n_orbitals, self.n_orbitals)) two_rdm = np.zeros((self.n_orbitals, self.n_orbitals, self.n_orbitals, self.n_orbitals)) # Loop over all single fermionic hamiltonian term to get RDM values all_terms = self.ferm_hamiltonian.terms import copy fh_copy = copy.deepcopy(self.ferm_hamiltonian) for ii in all_terms: for jj in ii[1]: # Only use a single fermionic term, set its coefficient to 1. term_type = ii[0] jj = (jj[0], 1.0) single_fh = (term_type, [jj]) fh_copy.terms = [single_fh] # Compute qubit Hamiltonian (C# Chemistry library) self.jw_hamiltonian = qsharpchem.encode(fh_copy, self.inputstate) # Compute RDM value RDM_value = self.simulate(amplitudes) # Update RDM matrices ferm_ops = single_fh[1][0][0][0] indices = [ferm_op[1] for ferm_op in ferm_ops] # 1-RDM matrix if (len(term_type) == 2): i, j = indices[0]//2, indices[1]//2 if (i == j): one_rdm[i, j] += RDM_value else: one_rdm[i, j] += RDM_value one_rdm[j, i] += RDM_value # 2-RDM matrix (works with Microsoft Chemistry library sign convention) elif (len(term_type) == 4): i, j, k, l = indices[0]//2, indices[1]//2, indices[2]//2, indices[3]//2 if((indices[0]==indices[3]) and (indices[1]==indices[2])): if((indices[0]%2 == indices[2]%2) and (indices[1]%2 == indices[3]%2)): two_rdm[i,l,j,k] += RDM_value two_rdm[j,k,i,l] += RDM_value two_rdm[i,k,j,l] -= RDM_value two_rdm[j,l,i,k] -= RDM_value else: two_rdm[i,l,j,k] += RDM_value two_rdm[j,k,i,l] += RDM_value else: if((indices[0]%2 == indices[3]%2) and (indices[1]%2 == indices[2]%2)): two_rdm[i,l,j,k] += RDM_value two_rdm[j,k,i,l] += RDM_value two_rdm[l,i,k,j] += RDM_value two_rdm[k,j,l,i] += RDM_value if((indices[0]%2 == indices[2]%2) and (indices[1]%2 == indices[3]%2)): two_rdm[i,k,j,l] -= RDM_value two_rdm[j,l,i,k] -= RDM_value two_rdm[k,i,l,j] -= RDM_value two_rdm[l,j,k,i] -= RDM_value else: two_rdm[i,k,j,l] -= RDM_value two_rdm[j,l,i,k] -= RDM_value two_rdm[k,i,l,j] -= RDM_value two_rdm[l,j,k,i] -= RDM_value return (one_rdm, two_rdm)
"|E1>", index_convention=IndexConvention.HalfUp) print("is2 ready.") logging.info(is2) #### # An end-to-end example of how to simulate H2: #### # Reload to make sure the quantum.qs file is correctly compiled: qsharp.reload() # Import the Q# operation into Python: from Microsoft.Quantum.Samples.Python import TrotterEstimateEnergy # load the broombridge data for H2: h2 = load_broombridge("h2.yaml") problem = h2.problem_description[0] fh = problem.load_fermion_hamiltonian() input_state = problem.load_input_state() # Once we have the hamiltonian and input state, we can call 'encode' to generate a Jordan-Wigner # representation, suitable for quantum simulation: qsharp_encoding = encode(fh, input_state) # Simulate the Q# operation: print('Starting simulation.') result = TrotterEstimateEnergy.simulate(qSharpData=qsharp_encoding, nBitsPrecision=10, trotterStepSize=.4) print(f'Trotter simulation complete. (phase, energy): {result}')