示例#1
0
def amplification_circuit(algorithm, oracle, qubits, num_iter):
    """
    Returns a program that does ``num_iter`` rounds of amplification, given a measurement-less
    algorithm, an oracle, and a list of qubits to operate on.

    :param Program algorithm: A program representing a measurement-less algorithm run on qubits.
    :param Program oracle: An oracle maps any basis vector ``|psi>`` to either ``+|psi>`` or
    ``-|psi>`` depending on whether ``|psi>`` is in the desirable subspace or the undesirable
    subspace.
    :param Sequence qubits: the qubits to operate on
    :param int num_iter: number of iterations of amplifications to run
    :return: The amplified algorithm.
    :rtype: Program
    """
    if num_iter <= 0:
        raise ValueError("num_iter must be greater than zero")

    prog = pq.Program()

    uniform_superimposer = pq.Program().inst([H(qubit) for qubit in qubits])
    prog += uniform_superimposer

    for _ in range(num_iter):
        prog += oracle + algorithm.dagger() + diffusion_program(qubits) + algorithm
    return prog
示例#2
0
    def _construct_deutsch_jozsa_circuit(self):
        """
        Builds the Deutsch-Jozsa circuit. Which can determine whether a function f mapping
        :math:`\{0,1\}^n \to \{0,1\}` is constant or balanced, provided that it is one of them.

        :return: A program corresponding to the desired instance of Simon's Algorithm.
        :rtype: Program
        """
        dj_prog = pq.Program()

        # Put the first ancilla qubit (query qubit) into minus state
        dj_prog.inst(X(self.ancillas[0]), H(self.ancillas[0]))

        # Apply Hadamard, Oracle, and Hadamard again
        dj_prog.inst([H(qubit) for qubit in self.computational_qubits])

        # Build the oracle
        oracle_prog = pq.Program()
        oracle_prog.defgate(ORACLE_GATE_NAME, self.unitary_matrix)

        scratch_bit = self.ancillas[1]
        qubits_for_funct = [scratch_bit] + self.computational_qubits
        oracle_prog.inst(tuple([ORACLE_GATE_NAME] + qubits_for_funct))
        dj_prog += oracle_prog

        # Here the oracle does not leave the computational qubits unchanged, so we use a CNOT to
        # to move the result to the query qubit, and then we uncompute with the dagger.
        dj_prog.inst(CNOT(self._qubits[0], self.ancillas[0]))
        dj_prog += oracle_prog.dagger()
        dj_prog.inst([H(qubit) for qubit in self.computational_qubits])
        return dj_prog
示例#3
0
def meyer_penny_program():
    """
    Returns the program to simulate the Meyer-Penny Game

    :return: pyQuil Program
    """

    picard_register = 1
    answer_register = 0

    then_branch = pq.Program(X(0))
    else_branch = pq.Program(I(0))

    return (pq.Program()
            # Prepare Qubits in Heads state or superposition, respectively
            .inst(X(0), H(1))
            # Q puts the coin into a superposition
            .inst(H(0))
            # Picard makes a decision and acts accordingly
            .measure(1, picard_register)
            .if_then(picard_register, then_branch, else_branch)
            # Q undoes his superposition operation
            .inst(H(0))
            # The outcome is recorded into the answer register
            .measure(0, answer_register))
示例#4
0
def meyer_penny_program():
    """
    Returns the program to simulate the Meyer-Penny Game
    The full description is available in ../docs/source/exercises.rst

    :return: pyQuil Program
    """
    prog = pq.Program()
    ro = prog.declare("ro", memory_size=2)
    picard_register = ro[1]
    answer_register = ro[0]

    then_branch = pq.Program(X(0))
    else_branch = pq.Program(I(0))

    # Prepare Qubits in Heads state or superposition, respectively
    prog.inst(X(0), H(1))
    # Q puts the coin into a superposition
    prog.inst(H(0))
    # Picard makes a decision and acts accordingly
    prog.measure(1, picard_register)
    prog.if_then(picard_register, then_branch, else_branch)
    # Q undoes his superposition operation
    prog.inst(H(0))
    # The outcome is recorded into the answer register
    prog.measure(0, answer_register)

    return prog
示例#5
0
def state_prep_classical(beta_value, start_qb):
    """
    Alternative state prep. Effectively creates an initial thermal state by clasically sampling a distribution
    and feeding that into the circuit.  rho_m = exp(-beta*H_M)/Z_m
    
    Input:
        beta_value: Inverse temperature to the initial qubits
        start_qb: Initialize on a specific qubit number to avoid dead qubits on
                  Rigetti
    Output:
        state_prep: A Rigetti Quil program for the initial state
        
    -------X^(classical outcome on qubit j)----- H -------
    """

    state_prep = pq.Program()
    for i in range(start_qb, num_good_qubits + start_qb, 1):
        tmp = pq.Program()
        samp = classical_sample(beta_value)
        if samp == 0:
            tmp.inst(H(i))
        else:
            tmp.inst(X(i), H(i))
        state_prep = state_prep + tmp
    return state_prep
示例#6
0
def weights_cost(nu_value, weights):
    """
    Implements exponential of 2-local terms (ZZ) of full cost Hamiltonian.
    
    Input:
        nu_value: pulse parameter
        weights: J_jk weights across all qubit pairs
    Output:
        weights_cost: Quil program creating weight cost Hamiltonian
    """

    assert (max(len(weights), len(weights[0])) <= num_good_qubits)

    weights_cost = pq.Program()
    for j in range(0, len(weights), 1):
        for k in range(0, len(weights[0]), 1):
            tmp = pq.Program()
            if j != k:
                tmp.inst(CNOT(j, k), RZ(2.0 * nu_value * weights[j][k], k),
                         CNOT(j, k))
            else:
                tmp.inst(RZ(2.0 * nu_value * weights[j][k], k))
            weights_cost = weights_cost + tmp

    return weights_cost
示例#7
0
文件: paulis.py 项目: dmitrip/pyquil
def _exponentiate_general_case(pauli_term, param):
    """
    Returns a Quil (Program()) object corresponding to the exponential of
    the pauli_term object, i.e. exp[-1.0j * param * pauli_term]

    :param pauli_term: (PauliTerm) to exponentiate
    :param param: scalar, non-complex, value

    :returns: A Quil (Program()) object
    """
    def reverse_hack(p):
        # A hack to produce a *temporary* program which reverses p.
        def translate(tup):
            action, obj = tup
            if tup == pqb.ACTION_RELEASE_QUBIT:
                return (pqb.ACTION_INSTANTIATE_QUBIT, obj)
            elif tup == pqb.ACTION_INSTANTIATE_QUBIT:
                return (pqb.ACTION_RELEASE_QUBIT, obj)
            else:
                return tup

        revp = pq.Program()
        revp.actions = map(translate, reversed(p.actions))
        return revp

    quil_prog = pq.Program()
    change_to_z_basis = pq.Program()
    change_to_original_basis = pq.Program()
    cnot_seq = pq.Program()
    prev_index = None
    highest_target_index = None

    for index, op in pauli_term:
        if 'X' == op:
            change_to_z_basis.inst(H(index))
            change_to_original_basis.inst(H(index))

        elif 'Y' == op:
            change_to_z_basis.inst(RX(np.pi / 2.0)(index))
            change_to_original_basis.inst(RX(-np.pi / 2.0)(index))

        elif 'I' == op:
            continue

        if prev_index is not None:
            cnot_seq.inst(CNOT(prev_index, index))

        prev_index = index
        highest_target_index = index

    # building rotation circuit
    quil_prog += change_to_z_basis
    quil_prog += cnot_seq
    quil_prog.inst(
        RZ(2.0 * pauli_term.coefficient * param)(highest_target_index))
    quil_prog += reverse_hack(cnot_seq)
    quil_prog += change_to_original_basis

    return quil_prog
    def _recursive_builder(self, operation, gate_name, control_qubits,
                           target_qubit):
        """Helper function used to define the controlled gate recursively. It uses the algorithm in
         the reference above. Namely it recursively constructs a controlled gate by applying a
         controlled square root of the gate, followed by a toffoli gate with len(control_qubits) - 1
         controls, applying the controlled adjoint of the square root, another toffoli with
         len(control_qubits) - 1 controls, and finally another controlled copy of the gate.

        :param numpy.ndarray operation: The matrix for the unitary to be controlled.
        :param String gate_name: The name for the gate being controlled.
        :param Sequence control_qubits: The qubits that are the controls.
        :param Qubit or Int target_qubit: The qubit that the gate should be applied to.
        :return: The intermediate Program being built.
        :rtype: Program
        """
        control_true = np.kron(ONE_PROJECTION, operation)
        control_false = np.kron(ZERO_PROJECTION, np.eye(2, 2))
        control_root_true = np.kron(ONE_PROJECTION, sqrtm(operation,
                                                          disp=True))
        controlled_gate = control_true + control_false
        controlled_root_gate = control_root_true + control_false
        sqrt_name = self.format_gate_name(SQRT_PREFIX, gate_name)
        controlled_subprogram = pq.Program()
        control_gate = pq.Program()
        # For the base case, we check to see if there is just one control qubit.
        # If it is a CNOT we explicitly break the naming convention so as not to redefine the gate.
        if len(control_qubits) == 1:
            if gate_name == NOT_GATE_LABEL:
                control_name = CONTROL_PREFIX + gate_name
            else:
                control_name = self.format_gate_name(CONTROL_PREFIX, gate_name)
            control_gate = self._defgate(control_gate, control_name,
                                         controlled_gate)
            control_gate.inst((control_name, control_qubits[0], target_qubit))
            return control_gate

        else:
            control_sqrt_name = self.format_gate_name(CONTROL_PREFIX,
                                                      sqrt_name)
            control_gate = self._defgate(control_gate, control_sqrt_name,
                                         controlled_root_gate)
            control_gate.inst(
                (control_sqrt_name, control_qubits[-1], target_qubit))
            # Here we recurse to build a toffoli gate on n - 1 of the qubits.
            n_minus_one_toffoli = self._recursive_builder(
                NOT_GATE, NOT_GATE_LABEL, control_qubits[:-1],
                control_qubits[-1])

            # We recurse to build a controlled sqrt of the target_gate, excluding the last control.
            n_minus_one_controlled_sqrt = self._recursive_builder(
                sqrtm(operation, disp=True), sqrt_name, control_qubits[:-1],
                target_qubit)
            controlled_subprogram += control_gate
            controlled_subprogram += n_minus_one_toffoli
            controlled_subprogram += control_gate.dagger()
            # We only add the instructions so that we don't redefine gates
            controlled_subprogram += n_minus_one_toffoli.instructions
            controlled_subprogram += n_minus_one_controlled_sqrt
            return controlled_subprogram
示例#9
0
文件: test_qft.py 项目: yevbar/grove
def test_simple_inverse_qft():

    trial_prog = pq.Program()
    trial_prog.inst(X(0))
    trial_prog = trial_prog + inverse_qft([0])

    result_prog = pq.Program().inst([X(0), H(0)])

    compare_progs(trial_prog, result_prog)
示例#10
0
def test_simple_inverse_qft():
    
    trial_prog = pq.Program()
    trial_prog.inst(X(0))
    trial_prog = trial_prog + inverse_qft([0])
    
    result_prog = pq.Program().inst([X(0), H(0)])
    
    assert trial_prog == result_prog
示例#11
0
def initialize_system(ancilla_qubit):
    """ Prepare initial state

    :param list ancilla_qubit: Qubit of ancilla register.
    :return Program p_ic: Quil program to initialize this system.
    """

    # ancilla qubit to plane wave state
    ic_ancilla = pq.Program([X(ancilla_qubit), H(ancilla_qubit)])
    p_ic = pq.Program(ic_ancilla)

    return p_ic
示例#12
0
def trotterize(first_pauli_term,
               second_pauli_term,
               trotter_order=1,
               trotter_steps=1):
    """
    Create a Quil program that approximates exp( (A + B)t) where A and B are
    PauliTerm operators.

    :param PauliTerm first_pauli_term: PauliTerm denoted `A`
    :param PauliTerm second_pauli_term: PauliTerm denoted `B`
    :param int trotter_order: Optional argument indicating the Suzuki-Trotter
                          approximation order--only accepts orders 1, 2, 3, 4.
    :param int trotter_steps: Optional argument indicating the number of products
                          to decompose the exponential into.

    :return: Quil program
    :rtype: Program
    """

    if not (1 <= trotter_order < 5):
        raise ValueError(
            "trotterize only accepts trotter_order in {1, 2, 3, 4}.")

    commutator = (first_pauli_term * second_pauli_term) +\
                 (-1 * second_pauli_term * first_pauli_term)

    prog = pq.Program()
    fused_param_prog = ParametricProgram(lambda: pq.Program())
    if is_zero(commutator):
        param_exp_prog_one = exponential_map(first_pauli_term)
        exp_prog = param_exp_prog_one(1)
        prog += exp_prog
        param_exp_prog_two = exponential_map(second_pauli_term)
        exp_prog = param_exp_prog_two(1)
        prog += exp_prog
        fused_param_prog = param_exp_prog_one.fuse(param_exp_prog_two)
        return prog, fused_param_prog

    order_slices = suzuki_trotter(trotter_order, trotter_steps)
    for coeff, operator in order_slices:
        if operator == 0:
            param_prog = exponential_map(coeff * first_pauli_term)
            exp_prog = param_prog(1)
            fused_param_prog = fused_param_prog.fuse(param_prog)
            prog += exp_prog
        else:
            param_prog = exponential_map(coeff * second_pauli_term)
            exp_prog = param_prog(1)
            fused_param_prog = fused_param_prog.fuse(param_prog)
            prog += exp_prog
    return prog, fused_param_prog
示例#13
0
def test_multi_qubit_qft():
    
    trial_prog = pq.Program()
    trial_prog.inst(X(0), X(1), X(2))
    trial_prog = trial_prog + inverse_qft([0, 1, 2])
    
    result_prog = pq.Program().inst([X(0), X(1), X(2),
                                     SWAP(0, 2), H(0),
                                     CPHASE(-1.5707963267948966, 0, 1),
                                     CPHASE(-0.7853981633974483, 0, 2),
                                     H(1), CPHASE(-1.5707963267948966, 1, 2),
                                     H(2)])
    
    assert trial_prog == result_prog
示例#14
0
def grover(oracle, qubits, query_qubit, num_iter=None):
    """
    Implementation of Grover's Algorithm for a given oracle.

    The query qubit will be left in the zero state afterwards.

    :param oracle: An oracle defined as a Program. It should send |x>|q> to |x>|q \oplus f(x)>,
                   where |q> is a a query qubit, and the range of f is {0, 1}.
    :param qubits: List of qubits for Grover's Algorithm. The last is assumed to be query for the
                   oracle.
    :param query_qubit: The qubit |q> that the oracle write its answer to.
    :param num_iter: The number of iterations to repeat the algorithm for. The default is
                     int(pi(sqrt(N))/4.
    :return: A program corresponding to the desired instance of Grover's Algorithm.
    """
    if len(qubits) < 1:
        raise ValueError("Grover's Algorithm requires at least 1 qubits.")

    if num_iter is None:
        num_iter = int(round(np.pi * 2**(len(qubits) / 2.0 - 2.0)))

    diff_op = diffusion_operator(qubits)
    def_gates = oracle.defined_gates + diff_op.defined_gates
    unique_gates = []
    seen_names = set()
    for gate in def_gates:
        if gate.name not in seen_names:
            seen_names.add(gate.name)
            unique_gates.append(gate)

    many_hadamard = pq.Program().inst(map(H, qubits))
    grover_iter = oracle + many_hadamard + diff_op + many_hadamard
    # To prevent redefining gates, this is not the preferred way.
    grover_iter.defined_gates = []

    prog = pq.Program()
    prog.defined_gates = unique_gates

    # Initialize ancilla to be in the minus state
    prog.inst(X(query_qubit))
    prog.inst(H(query_qubit))

    prog += many_hadamard
    for _ in xrange(num_iter):
        prog += grover_iter

    # Move the ancilla back to the zero state
    prog.inst(H(query_qubit))
    prog.inst(X(query_qubit))
    return prog
示例#15
0
def get_hhl_2x2(A, b, r, qubits):
    '''Generate a circuit that implements the full HHL algorithm for the case
    of 2x2 matrices.

    :param A: (numpy.ndarray) A Hermitian 2x2 matrix.
    :param b: (numpy.ndarray) A vector.
    :param r: (float) Parameter to be tuned in the algorithm.
    :param verbose: (bool) Optional information about the wavefunction.

    :return: A Quil program to perform HHL.
    '''
    p = pq.Program()
    p.inst(create_arbitrary_state(b, [qubits[3]]))
    p.inst(H(qubits[1]))
    p.inst(H(qubits[2]))
    p.defgate('CONTROLLED-U0', controlled(scipy.linalg.expm(2j*π*A/4)))
    p.inst(('CONTROLLED-U0', qubits[2], qubits[3]))
    p.defgate('CONTROLLED-U1', controlled(scipy.linalg.expm(2j*π*A/2)))
    p.inst(('CONTROLLED-U1', qubits[1], qubits[3]))
    p.inst(SWAP(qubits[1], qubits[2]))
    p.inst(H(qubits[2]))
    p.defgate('CSdag', controlled(np.array([[1, 0], [0, -1j]])))
    p.inst(('CSdag', qubits[1], qubits[2]))
    p.inst(H(qubits[1]))
    p.inst(SWAP(qubits[1], qubits[2]))
    uncomputation = p.dagger()
    p.defgate('CRy0', controlled(rY(2*π/2**r)))
    p.inst(('CRy0', qubits[1], qubits[0]))
    p.defgate('CRy1', controlled(rY(π/2**r)))
    p.inst(('CRy1', qubits[2], qubits[0]))
    p += uncomputation
    return p
示例#16
0
def test_one_qubit_exact_zeros_circuit():
    exact_one_qubit_bitmap = {"0": "0", "1": "1"}
    dj = DeutschJosza()
    with patch("pyquil.api.JobConnection") as qvm:
        # Should just be not the zero vector
        expected_bitstring = np.asarray([0, 1], dtype=int)
        qvm.run_and_measure.return_value = mock_job_result(expected_bitstring)
        _ = dj.is_constant(qvm, exact_one_qubit_bitmap)
    # Ordering doesn't matter, so we pop instructions from a set
    expected_prog = pq.Program()

    # We've defined the oracle and its dagger.
    dj_circuit = dj.deutsch_jozsa_circuit
    assert len(dj_circuit.defined_gates) == 2
    defined_oracle = None
    defined_oracle_inv = None
    for gate in dj_circuit.defined_gates:
        if gate.name == ORACLE_GATE_NAME:
            defined_oracle = gate
        else:
            defined_oracle_inv = gate

    assert defined_oracle is not None
    assert defined_oracle_inv is not None

    expected_prog.defgate(defined_oracle.name, defined_oracle.matrix)
    expected_prog.defgate(defined_oracle_inv.name, defined_oracle_inv.matrix)
    expected_prog.inst([
        X(1),
        H(1),
        H(0), (defined_oracle.name, 2, 0),
        CNOT(0, 1), (defined_oracle_inv.name, 2, 0),
        H(0)
    ])
    assert expected_prog.out() == dj.deutsch_jozsa_circuit.out()
def visualize_cost_matrix(qaoa_inst,
                          cost_operators,
                          number_of_qubits,
                          gammas=np.array([1.0]),
                          steps=1):
    from referenceqvm.api import QVMConnection as debug_QVMConnectiont
    debug_qvm = debug_QVMConnectiont(type_trans='unitary')
    param_prog, cost_param_programs = qaoa_inst.get_parameterized_program()
    import pyquil.quil as pq
    final_cost_prog = pq.Program()

    for idx in range(steps):
        for fprog in cost_param_programs[idx]:
            final_cost_prog += fprog(gammas[idx])

    final_matrix = debug_qvm.unitary(final_cost_prog)
    costs = np.diag(final_matrix)
    pure_costs = np.real(np.round(-np.log(costs) * 1j, 3))
    for i in range(2**self.number_of_qubits):
        print(np.binary_repr(i, width=self.number_of_qubits), pure_costs[i],
              np.round(costs[i], 3))
    most_freq_string, sampling_results = qaoa_inst.get_string(betas,
                                                              gammas,
                                                              samples=100000)
    print("Most common results")
    [print(el) for el in sampling_results.most_common()[:10]]
    print("Least common results")
    [print(el) for el in sampling_results.most_common()[-10:]]
    pdb.set_trace()
示例#18
0
文件: grover.py 项目: ryansk10/grove
def basis_selector_oracle(bitstring, qubits):
    """
    Defines an oracle that selects the ith element of the computational basis.

    Defines a phase filp rather than bit flip oracle to eliminate need
    for extra qubit. Flips the sign of the state :math:`\\vert x\\rangle>`
    if and only if x==bitstring and does nothing otherwise.

    :param bitstring: The desired bitstring,
                      given as a string of ones and zeros. e.g. "101"
    :param qubits: The qubits the oracle is called on.
                   The qubits are assumed to be ordered from most
                   significant qubit to least significant qubit.
    :return: A program representing this oracle.
    """
    if len(qubits) != len(bitstring):
        raise ValueError(
            "The bitstring should be the same length as the number of qubits.")
    if not (isinstance(bitstring, str)
            and all([num in ('0', '1') for num in bitstring])):
        raise ValueError("The bitstring must be a string of ones and zeros.")
    prog = pq.Program()
    for i, qubit in enumerate(qubits):
        if bitstring[i] == '0':
            prog.inst(X(qubit))

    prog += amp.n_qubit_control(qubits[:-1], qubits[-1],
                                np.array([[1, 0], [0, -1]]), 'Z')

    for i, qubit in enumerate(qubits):
        if bitstring[i] == '0':
            prog.inst(X(qubit))
    return prog
def test_phase_estimation():
    phase = 0.75
    precision = 4

    phase_factor = np.exp(1.0j * 2 * np.pi * phase)
    U = np.array([[phase_factor, 0], [0, -1 * phase_factor]])

    trial_prog = phase_estimation(U, precision)

    result_prog = pq.Program([H(i) for i in range(precision)])

    q_out = range(precision, precision + 1)
    for i in range(precision):
        if i > 0:
            U = np.dot(U, U)
        cU = controlled(U)
        name = "CONTROLLED-U{0}".format(2**i)
        result_prog.defgate(name, cU)
        result_prog.inst((name, i) + tuple(q_out))

    result_prog += inverse_qft(range(precision))

    result_prog += [MEASURE(i, [i]) for i in range(precision)]

    assert (trial_prog == result_prog)
示例#20
0
def basis_selector_oracle(bitstring, qubits, query_qubit):
    """
    Defines an oracle that selects the ith element of the computational basis.

    Sends the state |x>|q> -> |x>|!q> if x==bitstring and |x>|q> otherwise.

    :param bitstring: The desired bitstring, given as a string of ones and zeros. e.g. "101"
    :param qubits: The qubits the oracle is called on, the last of which is the query qubit. The
                   qubits are assumed to be ordered from most significant qubit to least signicant qubit.
    :param query_qubit: The qubit |q> that the oracle write its answer to.
    :return: A program representing this oracle.
    """
    if len(qubits) != len(bitstring):
        raise ValueError("The bitstring should be the same length as the number of qubits.")
    if not isinstance(query_qubit, Qubit):
        raise ValueError("query_qubit should be a single qubit.")
    if not (isinstance(bitstring, str) and all([num in ('0', '1') for num in bitstring])):
        raise ValueError("The bitstring must be a string of ones and zeros.")
    prog = pq.Program()
    for i, qubit in enumerate(qubits):
        if bitstring[i] == '0':
            prog.inst(X(qubit))

    prog += n_qubit_control(qubits, query_qubit, np.array([[0, 1], [1, 0]]), 'NOT')

    for i, qubit in enumerate(qubits):
        if bitstring[i] == '0':
            prog.inst(X(qubit))
    return prog
示例#21
0
文件: grover.py 项目: ryansk10/grove
def grover(oracle, qubits, num_iter=None):
    """
    Implementation of Grover's Algorithm for a given oracle.

    The query qubit will be left in the zero state afterwards.

    :param Program oracle: An oracle defined as a Program.
                           It should send |x> to (-1)^f(x)|x>,
                           where the range of f is {0, 1}.
    :param list(int) qubits: List of qubits for Grover's Algorithm.
    :param int num_iter: The number of iterations to repeat the algorithm for.
                         The default is the integer closest to
                         :math:`\\frac{\\pi}{4}\sqrt{N}`, where :math:`N` is
                         the size of the domain.
    :return: A program corresponding to
             the desired instance of Grover's Algorithm.
    :rtype: Program
    """
    if len(qubits) < 1:
        raise ValueError("Grover's Algorithm requires at least 1 qubits.")

    if num_iter is None:
        num_iter = int(round(np.pi * 2**(len(qubits) / 2.0 - 2.0)))

    many_hadamard = pq.Program().inst(list(map(H, qubits)))
    amp_prog = amp.amplify(many_hadamard, many_hadamard, oracle, qubits,
                           num_iter)

    return amp_prog
示例#22
0
    def _create_bv_circuit(self, bit_map):
        """
        Implementation of the Bernstein-Vazirani Algorithm.

        Given a list of input qubits and an ancilla bit, all initially in the
        :math:`\\vert 0\\rangle` state, create a program that can find :math:`\\vec{a}` with one
        query to the given oracle.

        :param Dict[String, String] bit_map: truth-table of a function for Bernstein-Vazirani with
        the keys being all possible bit vectors strings and the values being the function values
        :rtype: Program
        """
        unitary, _ = self._compute_unitary_oracle_matrix(bit_map)
        full_bv_circuit = pq.Program()

        full_bv_circuit.defgate("BV-ORACLE", unitary)

        # Put ancilla bit into minus state
        full_bv_circuit.inst(X(self.ancilla), H(self.ancilla))

        full_bv_circuit.inst([H(i) for i in self.computational_qubits])
        full_bv_circuit.inst(
            tuple(["BV-ORACLE"] + sorted(
                self.computational_qubits + [self.ancilla], reverse=True)))
        full_bv_circuit.inst([H(i) for i in self.computational_qubits])
        return full_bv_circuit
示例#23
0
def decomposed_diffusion_program(qubits):
    """
    Constructs the diffusion operator used in Grover's Algorithm, acted on both sides by an
    a Hadamard gate on each qubit. Note that this means that the matrix representation of this
    operator is diag(1, -1, ..., -1). In particular, this decomposes the diffusion operator, which
    is a :math:`2**{len(qubits)}\times2**{len(qubits)}` sparse matrix, into
     :math:`\mathcal{O}(len(qubits)**2) single and two qubit gates.

    See C. Lavor, L.R.U. Manssur, and R. Portugal (2003) `Grover's Algorithm: Quantum Database
    Search`_ for more information.

    .. _`Grover's Algorithm: Quantum Database Search`: https://arxiv.org/abs/quant-ph/0301079

    :param qubits: A list of ints corresponding to the qubits to operate on.
                   The operator operates on bistrings of the form
                   ``|qubits[0], ..., qubits[-1]>``.
    """
    program = pq.Program()
    if len(qubits) == 1:
        program.inst(Z(qubits[0]))
    else:
        program.inst([X(q) for q in qubits])
        program.inst(H(qubits[-1]))
        program.inst(RZ(-np.pi, qubits[0]))
        program += (ControlledProgramBuilder().with_controls(
            qubits[:-1]).with_target(qubits[-1]).with_operation(
                X_GATE).with_gate_name(X_GATE_LABEL).build())
        program.inst(RZ(-np.pi, qubits[0]))
        program.inst(H(qubits[-1]))
        program.inst([X(q) for q in qubits])
    return program
示例#24
0
def diffusion_operator(qubits):
    """Constructs the (Grover) diffusion operator on qubits, assuming they are ordered from most
    significant qubit to least significant qubit.

    The diffusion operator is the diagonal operator given by(1, -1, -1, ..., -1).

    :param qubits: A list of ints corresponding to the qubits to operate on. The operator
                   operates on bistrings of the form |qubits[0], ..., qubits[-1]>.
    """
    p = pq.Program()

    if len(qubits) == 1:
        p.inst(H(qubits[0]))
        p.inst(Z(qubits[0]))
        p.inst(H(qubits[0]))

    else:
        p.inst(map(X, qubits))
        p.inst(H(qubits[-1]))
        p.inst(RZ(-np.pi)(qubits[0]))
        p += n_qubit_control(qubits[:-1], qubits[-1], np.array([[0, 1], [1, 0]]), "NOT")
        p.inst(RZ(-np.pi)(qubits[0]))
        p.inst(H(qubits[-1]))
        p.inst(map(X, qubits))
    return p
示例#25
0
def oracle_function(unitary_funct, qubits, ancilla):
    """
    Defines an oracle that performs the following unitary transformation:
    |x>|y> -> |x>|f(x) xor y>

    Allocates one scratch bit.

    :param np.array unitary_funct: Matrix representation of the function f, i.e. the
        unitary transformation that must be applied to a state |x> to put f(x) in qubit 0, where
        f(x) returns either 0 or 1 for any n-bit string x
    :param np.array qubits: List of qubits that enter as input |x>.
    :param Qubit ancilla: Qubit to serve as input |y>.
    :return: A program that performs the above unitary transformation.
    :rtype: Program
    """
    if not is_unitary(unitary_funct):
        raise ValueError("Function must be unitary.")
    p = pq.Program()
    scratch_bit = p.alloc()
    bits_for_funct = [scratch_bit] + qubits
    p.defgate("FUNCT", unitary_funct)
    p.defgate("FUNCT-INV", unitary_funct.T.conj())
    # TODO Remove the cast to tuple once this is supported.
    p.inst(tuple(['FUNCT'] + bits_for_funct))
    p.inst(CNOT(qubits[0], ancilla))
    p.inst(tuple(['FUNCT-INV'] + bits_for_funct))
    p.free(scratch_bit)
    return p
示例#26
0
def bernstein_vazirani(oracle, qubits, ancilla):
    """
    Implementation of the Bernstein-Vazirani Algorithm.

    Given a list of input qubits and an ancilla bit,
    all initially in the :math:`\\vert 0\\rangle` state,
    create a program that can find :math:`\\vec{a}`
    with one query to the given oracle.

    :param Program oracle: Program representing unitary application of function
    :param list(int) qubits: List of qubits that enter as state
                             :math:`\\vert x\\rangle`.
    :param int ancilla: Ancillary qubit to serve as input
                        :math:`\\vert y\\rangle`,
                        where the answer will be written to.
    :return: A program corresponding to the desired instance of the
             Bernstein-Vazirani Algorithm.
    :rtype: Program
    """
    p = pq.Program()

    # Put ancilla bit into minus state
    p.inst(X(ancilla), H(ancilla))

    # Apply Hadamard, Unitary function, and Hadamard again
    p.inst(list(map(H, qubits)))
    p += oracle
    p.inst(list(map(H, qubits)))
    return p
示例#27
0
def test_gradient_program():
    f_h = 0.25
    precision = 2

    trial_prog = gradient_program(f_h, precision)

    result_prog = pq.Program([H(0), H(1)])

    phase_factor = np.exp(-1.0j * 2 * np.pi * abs(f_h))
    U = np.array([[phase_factor, 0], [0, phase_factor]])
    q_out = range(precision, precision + 1)
    for i in range(precision):
        if i > 0:
            U = np.dot(U, U)
        cU = controlled(U)
        name = "CONTROLLED-U{0}".format(2**i)
        result_prog.defgate(name, cU)
        result_prog.inst((name, i) + tuple(q_out))

    result_prog.inst([
        H(1),
        CPHASE(1.5707963267948966, 0, 1),
        H(0),
        SWAP(0, 1),
        MEASURE(0, [0]),
        MEASURE(1, [1])
    ])

    assert (trial_prog == result_prog)
示例#28
0
    def expectation(self, prep_prog, operator_programs=None):
        """
        Calculate the expectation value of operators given a state prepared by
        prep_program.

        :param Program prep_prog: Quil program for state preparation.
        :param list operators: A list of PauliTerms. Default is Identity operator.
        :returns: Expectation value of the operators.
        :rtype: float
        """
        if operator_programs is None:
            operator_programs = [pq.Program()]

        if not isinstance(prep_prog, pq.Program):
            raise TypeError("prep_prog variable must be a Quil program object")

        payload = {
            'type': TYPE_EXPECTATION,
            'state-preparation': prep_prog.out(),
            'operators': [x.out() for x in operator_programs]
        }

        add_rng_seed_to_payload(payload, self.random_seed)

        res = self.post_job(payload, headers=self.json_headers)
        return self.process_response(res)
示例#29
0
def diffusion_program(qubits):
    """Constructs the diffusion operator used in Grover's Algorithm, acted on both sides by an
     a Hadamard gate on each qubit. Note that this means that the matrix representation of this
     operator is diag(1, -1, ..., -1).

    See C. Lavor, L.R.U. Manssur, and R. Portugal (2003) `Grover's Algorithm: Quantum Database
    Search`_ for more information.

    .. _`Grover's Algorithm: Quantum Database Search`: https://arxiv.org/abs/quant-ph/0301079

    :param qubits: A list of ints corresponding to the qubits to operate on.
                   The operator operates on bistrings of the form
                   |qubits[0], ..., qubits[-1]>.
    """
    diffusion_program = pq.Program()

    if len(qubits) == 1:
        diffusion_program.inst(Z(qubits[0]))
    else:
        diffusion_program.inst([X(q) for q in qubits])
        diffusion_program.inst(H(qubits[-1]))
        diffusion_program.inst(RZ(-np.pi)(qubits[0]))
        diffusion_program += (ControlledProgramBuilder()
                              .with_controls(qubits[:-1])
                              .with_target(qubits[-1])
                              .with_operation(X_GATE)
                              .with_gate_name("NOT").build())
        diffusion_program.inst(RZ(-np.pi)(qubits[0]))
        diffusion_program.inst(H(qubits[-1]))
        diffusion_program.inst([X(q) for q in qubits])
    return diffusion_program
示例#30
0
        def psi_ref(params):
            """Construct a Quil program for the vector (beta, gamma).

            :param params: array of 3 . p angles, betas first, then gammas, then omega
            :return: a pyquil program object
            """
            if len(params) != 3 * self.steps:
                raise ValueError(
                    """params doesn't match the number of parameters set
                                    by `steps`""")

            betas = params[:self.steps]
            gammas = params[self.steps:2 * self.steps]
            omegas = params[2 * self.steps:]

            prog = pq.Program()
            prog += self.ref_state_prep
            for idx in range(self.steps):

                for fprog in constraint_para_programs[idx]:
                    prog += fprog(gammas[idx])

                for fprog in localfield_para_programs[idx]:
                    prog += fprog(omegas[idx])

                for fprog in driver_para_programs[idx]:
                    prog += fprog(betas[idx])
            return prog