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
예제 #2
0
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))
예제 #3
0
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
예제 #5
0
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
예제 #6
0
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))
예제 #8
0
def test_exponentiate_prog():
    ham = PauliTerm("Z", 0)
    result_prog = Program(RZ(2.0, 0))
    prog = exponentiate(ham)
    compare_progs(result_prog, prog)
예제 #9
0
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)
예제 #12
0
    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)
예제 #14
0
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))