def Ising_prog_3(n, t): '''Definition of a function to obtain a sequence of gates for an Ising chain with H = -0.5*(1/|i-j|)*sigma_x_i*sigma_x_j - 0.5*sigma_x_j - 0.5*sigma_z_j where index i j run from 0th to (n-1)th site and i is always smaller than j. Here 3rd-order Trotter approximant is applied. param n: number of qubits (n>=2). param t: evolution time.''' from pyquil.paulis import exponentiate factor = -0.5 prog = Program() # The coefficients of exponential operators coef_lis = [7 / 24, 2 / 3, 3 / 4, -2 / 3, -1 / 24, 1] for i in np.arange(len(comb_xx(n))): prog_ini = Program() prog_ini += trotterize(t * factor * coef_lis[0] * comb_xx(n)[i], t * factor * coef_lis[0] * comb_x(n)[i], trotter_order=3) prog_ini += exponentiate(t * factor * coef_lis[1] * comb_z(n)[i]) prog_ini += trotterize(t * factor * coef_lis[2] * comb_xx(n)[i], t * factor * coef_lis[2] * comb_x(n)[i], trotter_order=3) prog_ini += exponentiate(t * factor * coef_lis[3] * comb_z(n)[i]) prog_ini += trotterize(t * factor * coef_lis[4] * comb_xx(n)[i], t * factor * coef_lis[4] * comb_x(n)[i], trotter_order=3) prog_ini += exponentiate(t * factor * coef_lis[5] * comb_z(n)[i]) prog += prog_ini return prog
def test_exp_circuit(): true_wf = np.array( [ 0.54030231 - 0.84147098j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, 0.00000000 + 0.0j, ] ) create2kill1 = PauliTerm("X", 1, -0.25) * PauliTerm("Y", 2) create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("Y", 2) create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("X", 2) create2kill1 += PauliTerm("X", 1, 0.25) * PauliTerm("X", 2) create2kill1 += PauliTerm("I", 0, 1.0) prog = Program() for term in create2kill1.terms: single_exp_prog = exponentiate(term) prog += single_exp_prog qam = PyQVM(n_qubits=3, quantum_simulator_type=ReferenceWavefunctionSimulator) qam.execute(prog) wf = qam.wf_simulator.wf np.testing.assert_allclose(wf.dot(np.conj(wf).T), true_wf.dot(np.conj(true_wf).T))
def time_evolution(hamiltonian: pyquil.paulis.PauliSum, time: float, method: str = 'Trotter', trotter_order: int = 1) -> Circuit: """Generates circuit for performing time evolution under a Hamiltonian H. The default setting is first-order Trotterization. The goal is to approximate the operation exp(-iHt). Args: hamiltonian: pyquil.paulis.PauliSum The Hamiltonian to be evolved under. time: float Time duration of the evolution. method (str): Time evolution method. Currently the only option is 'Trotter'. trotter_order (int): order of Trotter evolution Returns: A Circuit (core.circuit) object representing the time evolution. """ if method == 'Trotter': output = pyquil.Program() for index_order in range(0, trotter_order): # iterate over Trotter orders for index_term in range(0, len(hamiltonian.terms)): pyquil_expitH_circuit = exponentiate(hamiltonian[index_term] * (time / trotter_order)) output += pyquil_expitH_circuit else: raise ValueError( 'Currently the method {} is not supported'.format(method)) return Circuit(output)
def Ising_prog_4(n, t): '''Definition of a function to obtain a sequence of gates for an Ising chain with H = -0.5*(1/|i-j|)*sigma_x_i*sigma_x_j - 0.5*sigma_x_j - 0.5*sigma_z_j where index i j run from 0th to (n-1)th site and i is always smaller than j. Here 4th-order Trotter approximant is applied. param n: number of qubits (n>=2). param t: evolution time.''' from pyquil.paulis import exponentiate factor = -0.5 prog = Program() # The coefficient k2 coef_k = 1 / (4 - 4**(1 / 3)) for i in np.arange(len(comb_xx(n))): prog_ini = Program() prog_ini += trotterize(t * factor * (coef_k / 2) * comb_xx(n)[i], t * factor * (coef_k / 2) * comb_x(n)[i], trotter_order=4) prog_ini += exponentiate(t * factor * coef_k * comb_z(n)[i]) prog_ini += trotterize(t * factor * coef_k * comb_xx(n)[i], t * factor * coef_k * comb_x(n)[i], trotter_order=4) prog_ini += exponentiate(t * factor * coef_k * comb_z(n)[i]) prog_ini += trotterize( t * factor * ((1 - 3 * coef_k) / 2) * comb_xx(n)[i], t * factor * ((1 - 3 * coef_k) / 2) * comb_x(n)[i], trotter_order=4) prog_ini += exponentiate(t * factor * (1 - 4 * coef_k) * comb_z(n)[i]) prog_ini += trotterize( t * factor * ((1 - 3 * coef_k) / 2) * comb_xx(n)[i], t * factor * ((1 - 3 * coef_k) / 2) * comb_x(n)[i], trotter_order=4) prog_ini += exponentiate(t * factor * coef_k * comb_z(n)[i]) prog_ini += trotterize(t * factor * coef_k * comb_xx(n)[i], t * factor * coef_k * comb_x(n)[i], trotter_order=4) prog_ini += exponentiate(t * factor * coef_k * comb_z(n)[i]) prog_ini += trotterize(t * factor * (coef_k / 2) * comb_xx(n)[i], t * factor * (coef_k / 2) * comb_x(n)[i], trotter_order=4) prog += prog_ini return prog
def ucc_circuit(theta): """ Implements exp(-i theta X_{0}Y_{1}) :param theta: rotation parameter :return: pyquil.Program """ generator = sX(0) * sY(1) initial_prog = Program().inst(X(1), X(0)) # compiled program program = initial_prog + exponentiate( float(theta) * generator ) # float is required because pyquil has weird casting behavior return program
def test_exp_circuit(qvm): true_wf = np.array([ 0.54030231 - 0.84147098j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j, 0.00000000 + 0.j ]) create2kill1 = PauliTerm("X", 1, -0.25) * PauliTerm("Y", 2) create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("Y", 2) create2kill1 += PauliTerm("Y", 1, 0.25) * PauliTerm("X", 2) create2kill1 += PauliTerm("X", 1, 0.25) * PauliTerm("X", 2) create2kill1 += PauliTerm("I", 0, 1.0) prog = Program() for term in create2kill1.terms: single_exp_prog = exponentiate(term) prog += single_exp_prog wf, _ = qvm.wavefunction(prog) wf = np.reshape(wf.amplitudes, -1) assert np.allclose(wf.dot(np.conj(wf).T), true_wf.dot(np.conj(true_wf).T))
def trotterization(hamiltonian, time, trotter_order): """ Uses first order Trotter-Suzuki decomposition: exp(iHt) = (exp(ih_1 t)exp(ih_2 t)exp(ih_n t))^N + O(t*delta_t), where H = h_1 * h_2 * ... * h_n, delta_t is t/N :param hamiltonian: is the Hamiltonian (H in the formula) :param time: is t in the formula :param trotter_order: is N in the formula. :return: Trotterized exponentiated Hamiltonian """ delta_time = time / trotter_order trotter_order1_program = Program() for term in hamiltonian.terms: # Note that exponentiate(term) returns exp(-1j * term) trotter_order1_program += exponentiate(-delta_time * term) return repeat_program(trotter_order1_program, int(trotter_order))
def test_exponentiate_prog(): ham = PauliTerm("Z", 0) result_prog = Program(RZ(2.0, 0)) prog = exponentiate(ham) compare_progs(result_prog, prog)
def test_exponentiate_prog(): ham = PauliTerm("Z", 0) result_prog = Program(RZ(2.0, 0)) prog = exponentiate(ham) assert prog == result_prog
def test_exponentiate_prog(): q = QubitPlaceholder.register(8) ham = PauliTerm("Z", q[0]) result_prog = Program(RZ(2.0, q[0])) prog = exponentiate(ham) assert address_qubits(prog) == address_qubits(result_prog)
from openfermion.utils import hermitian_conjugated from forestopenfermion import qubitop_to_pyquilpauli, pyquilpauli_to_qubitop from pyquil.quil import Program from pyquil.gates import X from pyquil.paulis import exponentiate from pyquil.api import QVMConnection hubbard_hamiltonian = FermionOperator() spatial_orbitals = 4 for i in range(spatial_orbitals): electron_hop_alpha = FermionOperator(((2*i, 1), (2*((i+1) % spatial_orbitals), 0))) electron_hop_beta = FermionOperator(((2*i+1, 1), ((2 * ((i+1) % spatial_orbitals) + 1), 0))) hubbard_hamiltonian += -1 * (electron_hop_alpha + hermitian_conjugated(electron_hop_alpha)) hubbard_hamiltonian += -1 * (electron_hop_beta + hermitian_conjugated(electron_hop_beta)) hubbard_hamiltonian += FermionOperator(((2*i, 1), (2*i, 0), (2*i+1, 1), (2*i+1, 0)), 4.0) hubbard_term_generator = jordan_wigner(hubbard_hamiltonian) pyquil_hubbard_generator = qubitop_to_pyquilpauli(hubbard_term_generator) localized_electrons_program = Program() localized_electrons_program.inst([X(0), X(1)]) pyquil_program = Program() for term in pyquil_hubbard_generator.terms: pyquil_program += exponentiate(0.1*term) print (localized_electrons_program + pyquil_program) qvm = QVMConnection() print(qvm.run(pyquil_program, [0], 10)) wf = qvm.wavefunction(pyquil_program) print(wf)
def simulate(self, amplitudes): """Perform the simulation for the molecule. Args: amplitudes (list): The initial amplitudes (float64). Returns: float64: The total energy (energy). Raise: ValueError: If the dimension of the amplitude list is incorrect. """ if len(amplitudes) != self.amplitude_dimension: raise ValueError("Incorrect dimension for amplitude list.") #Anti-hermitian operator and its qubit form generator = uccsd_singlet_generator(amplitudes, self.of_mole.n_qubits, self.of_mole.n_electrons) jw_generator = jordan_wigner(generator) pyquil_generator = qubitop_to_pyquilpauli(jw_generator) p = Program(Pragma('INITIAL_REWIRING', ['"GREEDY"'])) # Set initial wavefunction (Hartree-Fock) for i in range(self.of_mole.n_electrons): p.inst(X(i)) # Trotterization (unitary for UCCSD state preparation) for term in pyquil_generator.terms: term.coefficient = np.imag(term.coefficient) p += exponentiate(term) p.wrap_in_numshots_loop(self.backend_options["n_shots"]) # Do not simulate if no operator was passed if len(self.qubit_hamiltonian.terms) == 0: return 0. else: # Run computation using the right backend if isinstance(self.backend_options["backend"], WavefunctionSimulator): energy = self.backend_options["backend"].expectation( prep_prog=p, pauli_terms=self.forest_qubit_hamiltonian) else: # Set up experiment, each setting corresponds to a particular measurement basis settings = [ ExperimentSetting(in_state=TensorProductState(), out_operator=forest_term) for forest_term in self.forest_qubit_hamiltonian.terms ] experiment = TomographyExperiment(settings=settings, program=p) print(experiment, "\n") results = self.backend_options["backend"].experiment( experiment) energy = 0. coefficients = [ forest_term.coefficient for forest_term in self.forest_qubit_hamiltonian.terms ] for i in range(len(results)): energy += results[i].expectation * coefficients[i] energy = np.real(energy) # Save the amplitudes so we have the optimal ones for RDM calculation self.optimized_amplitudes = amplitudes return energy
multiplicity = 1 bond_length = 1.0 geometry = [('H', (0., 0., 0.)), ('H', (0., 0., bond_length))] description = str(round(bond_length, 2)) molecule = MolecularData(geometry, basis, multiplicity, description=description) molecule = run_pyscf(molecule, run_mp2=True, run_cisd=True, run_ccsd=True, run_fci=True) # This is the Qubit hamiltonian that we obtain using the Jordan-Wigner transformation h2_qubit_hamiltonian = jordan_wigner( get_fermion_operator(molecule.get_molecular_hamiltonian())) # The qubit operator obtained is later converted to pyquil operatiors using an # openfermion plugin called forestopenfermion pyquil_hamiltonian = qubitop_to_pyquilpauli(h2_qubit_hamiltonian) # With the data successfully transformed to pyquil transformation, the pyquil exponentiate routine is # used to generate a quantum circuit corrensponding to the first-order Trotter evolution corresponding for t = 0.1s pyquil_program = Program() for term in pyquil_hamiltonian.terms: pyquil_hamiltonian += exponentiate(0.1 * term) print(pyquil_program)
def time_evolution_derivatives( hamiltonian: pyquil.paulis.PauliSum, time: float, method: str = 'Trotter', trotter_order: int = 1) -> Tuple[List[Circuit], List[float]]: """Generates derivative circuits for the time evolution operator defined in function time_evolution Args: hamiltonian: pyquil.paulis.PauliSum The Hamiltonian to be evolved under. time: float Time duration of the evolution. method (str): Time evolution method. Currently the only option is 'Trotter'. trotter_order (int): order of Trotter evolution Returns: A Circuit (core.circuit) object representing the time evolution. """ if method == 'Trotter': # derivative for a single Trotter step single_trotter_derivatives = [] factors = [1.0, -1.0] output_factors = [] for index_term1 in range(0, len(hamiltonian.terms)): for factor in factors: output = pyquil.Program() # r is the eigenvalue of the generator of the gate. The value is modified # to take into account the coefficient and trotter step in front of the # Pauli term r = hamiltonian[index_term1].coefficient.real / trotter_order output_factors.append(factor * r) shift = factor * (np.pi / (4.0 * r)) for index_term2 in range(0, len(hamiltonian.terms)): if index_term1 == index_term2: pyquil_expitH_circuit = exponentiate(hamiltonian[index_term2]\ * ((time + shift) / trotter_order)) output += pyquil_expitH_circuit else: pyquil_expitH_circuit = exponentiate(hamiltonian[index_term2]\ * (time / trotter_order)) output += pyquil_expitH_circuit single_trotter_derivatives.append(Circuit(output)) if trotter_order > 1: output_circuits = [] final_factors = [] repeated_circuit = time_evolution(hamiltonian, time, method='Trotter', trotter_order=1) for position in range(0, trotter_order): for circuit_factor, different_circuit in zip( output_factors, single_trotter_derivatives): output_circuits.append( generate_circuit_sequence(repeated_circuit, different_circuit, trotter_order, position)) final_factors.append(circuit_factor) return output_circuits, final_factors else: return single_trotter_derivatives, output_factors else: raise ValueError( 'Currently the method {} is not supported'.format(method))