Esempio n. 1
0
 def carry_gate():
     carry_circ = AncillaCircuit(4)
     (c0, a, b, c1) = (carry_circ.qubits[0], carry_circ.qubits[1],
                       carry_circ.qubits[2], carry_circ.qubits[3])
     carry_circ.ccx(a, b, c1)
     carry_circ.append(neg_mct_gate(), [c0, a, b, c1])
     return carry_circ.to_ancilla_gate()
Esempio n. 2
0
 def qc_amplitude_amplification_iteration():
     reg = QuantumRegister(n + 1, name='reg')
     _qc_aa_iteration = AncillaCircuit(QuantumRegister(n + 1))
     _qc_aa_iteration.append(oracle, reg)
     _qc_aa_iteration.append(
         _construct_diffusion_circuit().to_ancilla_gate(), reg[:-1])
     return _qc_aa_iteration
Esempio n. 3
0
def makesGroverCircuit(n, oracle=None, nb_sols=1):
    # grover circuit on n qubits, without measurements as uncomp cannot deal with that yet
    nbIter = int(np.floor(np.pi / 4.0 * np.sqrt(pow(2, n))))

    working_qubits = QuantumRegister(n, name='r')
    phase_qubit = QuantumRegister(1, name='p')
    circ = AncillaCircuit(working_qubits, phase_qubit)
    circ.x(phase_qubit[0])
    circ.h(phase_qubit[0])

    circ.h(working_qubits)

    for l in range(nbIter):
        if oracle:
            circ.append(oracle, [*working_qubits[:], phase_qubit[0]])
        else:
            circ.mcx(working_qubits, phase_qubit)

        #Grover diffusion operator
        circ.h(working_qubits)

        circ.x(working_qubits)
        circ.h(working_qubits[-1])
        circ.mcx(working_qubits[:-1], working_qubits[-1])
        circ.h(working_qubits[-1])
        circ.x(working_qubits)

        circ.h(working_qubits)

    # bring the phase qubit back to 0, we can't uncompute it, as it went through cz, non qfree -> no need to uncomp it, Qiskit doesn't
    #circ.h(phase_qubit[0])
    #circ.x(phase_qubit)
    return (circ, working_qubits)
Esempio n. 4
0
def makeIntegerComparator(num_state_qubits, value, geq=True, with_uncomp=True):
    """Build the comparator circuit."""
    or_gate = OR(2).to_gate()
    qr_state = QuantumRegister(num_state_qubits, name='state')
    q_compare = QuantumRegister(1, name='compare')
    circuit = AncillaCircuit(qr_state, q_compare)
    circuit.addQfreeGate(or_gate)
    qr_ancilla = circuit.new_ancilla_register(
        num_state_qubits - 1, name='ancilla') if num_state_qubits > 1 else None

    if value <= 0:  # condition always satisfied for non-positive values
        if geq:  # otherwise the condition is never satisfied
            circuit.x(q_compare)
    # condition never satisfied for values larger than or equal to 2^n
    elif value < pow(2, num_state_qubits):

        if num_state_qubits > 1:
            twos = _get_twos_complement(num_state_qubits, value)
            for i in range(num_state_qubits):
                if i == 0:
                    if twos[i] == 1:
                        circuit.cx(qr_state[i], qr_ancilla[i])
                elif i < num_state_qubits - 1:
                    if twos[i] == 1:
                        circuit.append(
                            or_gate,
                            [qr_state[i], qr_ancilla[i - 1], qr_ancilla[i]])
                    else:
                        circuit.ccx(qr_state[i], qr_ancilla[i - 1],
                                    qr_ancilla[i])
                else:
                    if twos[i] == 1:
                        circuit.append(
                            or_gate,
                            [qr_state[i], qr_ancilla[i - 1], q_compare])
                    else:
                        circuit.ccx(qr_state[i], qr_ancilla[i - 1], q_compare)

            # flip result bit if geq flag is false
            if not geq:
                circuit.x(q_compare)

        else:

            # num_state_qubits == 1 and value == 1:
            circuit.cx(qr_state[0], q_compare)

            # flip result bit if geq flag is false
            if not geq:
                circuit.x(q_compare)

    else:
        if not geq:  # otherwise the condition is never satisfied
            circuit.x(q_compare)

    return circuit
Esempio n. 5
0
def makesMult(num_qubits):
    #[x, y, b] b = x * y; x, y, and b all made of num_qubits each
    #returns an AncillaCircuit, without uncomputation
    b = QuantumRegister(num_qubits)
    y = QuantumRegister(num_qubits)
    x = QuantumRegister(num_qubits)

    circuit = AncillaCircuit(b, y, x)

    for i, x_i in enumerate(x):
        # a = (y*(2**i))*x_i
        a = circuit.new_ancilla_register(num_qubits)
        for a_qubit, y_qubit in zip(a[i:], y[:num_qubits - i]):
            circuit.ccx(x_i, y_qubit, a_qubit)
        # b += a
        circuit.append(
            makesAdder(num_qubits).to_ancilla_gate(), [*a[:], *b[:]])

    return circuit
Esempio n. 6
0
def makesDJ(num_qubits, oracle_gate=None):
    #Builds the Deutsch Jozsa circuit for n + 1 qubits, finding the value 111...111
    var_reg = QuantumRegister(num_qubits, name='vals')
    out_reg = QuantumRegister(1, name='out')

    circ = AncillaCircuit(var_reg, out_reg)

    circ.h(var_reg)
    circ.x(out_reg)
    circ.h(out_reg)

    if oracle_gate:
        circ.append(oracle_gate, [*var_reg, out_reg[0]])
    else:
        circ.mcx(var_reg, out_reg)

    circ.h(var_reg)

    return (circ, var_reg)
Esempio n. 7
0
def GroverQpp(
        n, oracle
):  # oracle should be an ancilla gate on n + 1 qb, result in last qb
    _num_iterations = int(np.floor(np.pi / 4.0 * np.sqrt(pow(2, n))))

    def _construct_diffusion_circuit():
        num_variable_qubits = n
        var_reg2 = QuantumRegister(num_variable_qubits)
        qc = AncillaCircuit(var_reg2)

        qc.h(var_reg2)
        qc.u(np.pi, 0, np.pi, var_reg2)
        qc.u(np.pi / 2, 0, np.pi, var_reg2[-1])
        qc.mcx(var_reg2[:-1], var_reg2[-1])
        qc.u(np.pi / 2, 0, np.pi, var_reg2[-1])
        qc.u(np.pi, 0, np.pi, var_reg2)
        qc.h(var_reg2)
        return qc

    def qc_amplitude_amplification_iteration():
        reg = QuantumRegister(n + 1, name='reg')
        _qc_aa_iteration = AncillaCircuit(QuantumRegister(n + 1))
        _qc_aa_iteration.append(oracle, reg)
        _qc_aa_iteration.append(
            _construct_diffusion_circuit().to_ancilla_gate(), reg[:-1])
        return _qc_aa_iteration

    var_reg = QuantumRegister(n, name='var_reg')
    out_reg = QuantumRegister(1, name='out_reg')
    qc = AncillaCircuit(var_reg, out_reg)
    qc.u(np.pi, 0, np.pi, out_reg)  # x
    qc.u(np.pi / 2, 0, np.pi, out_reg)  # h
    qc.h(var_reg)
    for _ in range(_num_iterations):
        qc.append(qc_amplitude_amplification_iteration().to_ancilla_gate(),
                  [*var_reg, out_reg])

    return (qc, var_reg)
Esempio n. 8
0
def makesAdder(num_qubits):
    #[a, b, s]: s = a + b, a and b made of num_qubits each
    # returns an AncillaCircuit, without uncomputation
    def neg_mct_gate(lneg):
        neg_mct = AncillaCircuit(3)
        for i in lneg:
            neg_mct.x(i)
        neg_mct.ccx(0, 1, 2)
        for i in lneg:
            neg_mct.x(i)
        return neg_mct.to_ancilla_gate(True)

    a = QuantumRegister(num_qubits, name="a")
    b = QuantumRegister(num_qubits, name="b")
    s = QuantumRegister(num_qubits, name="s")
    c = AncillaRegister(num_qubits, name="c")

    circuit = AncillaCircuit(a, b, s, c)

    for i in range(num_qubits - 1):
        #sum
        t = circuit.new_ancilla_register(1, name='t' + str(i))
        circuit.cx(a[i], t)
        circuit.cx(b[i], t)  #to be quipper like
        circuit.cx(t, s[i])
        circuit.cx(c[i], s[i])

        #carry
        v = circuit.new_ancilla_register(1, name='v' + str(i))
        circuit.append(neg_mct_gate([0, 1]), [a[i], b[i], v])
        circuit.append(neg_mct_gate([1]), [v, c[i], c[i + 1]])
        circuit.x(c[i + 1])

    circuit.cx(a[num_qubits - 1], s[num_qubits - 1])
    circuit.cx(b[num_qubits - 1], s[num_qubits - 1])
    circuit.cx(c[num_qubits - 1], s[num_qubits - 1])

    return circuit
Esempio n. 9
0
def makesPLR(num_state_qubits, breakpoints, slopes, offsets):
    qr_state = QuantumRegister(num_state_qubits, name='state')
    qr_target = QuantumRegister(1, name='target')
    circuit = AncillaCircuit(qr_state, qr_target)

    mapped_slopes = np.zeros_like(slopes)
    for i, slope in enumerate(slopes):
        mapped_slopes[i] = slope - sum(mapped_slopes[:i])

    mapped_offsets = np.zeros_like(offsets)
    for i, (offset, slope,
            point) in enumerate(zip(offsets, slopes, breakpoints)):
        mapped_offsets[i] = offset - slope * point - sum(mapped_offsets[:i])

    basis = 'Y'

    # apply comparators and controlled linear rotations
    for i, point in enumerate(breakpoints):
        if i == 0 and _contains_zero_breakpoint(breakpoints):
            # apply rotation
            lin_r = LinearPauliRotations(num_state_qubits=num_state_qubits,
                                         slope=mapped_slopes[i],
                                         offset=mapped_offsets[i],
                                         basis='Y')
            circuit.append(lin_r.to_gate(), qr_state[:] + [qr_target])

        else:

            comp_ancilla = circuit.new_ancilla_register(1, name='ac' + str(i))
            circuit.append(
                makeIntegerComparator(num_state_qubits,
                                      point).to_ancilla_gate(),
                [*qr_state[:], comp_ancilla[0]])

            # apply controlled rotation
            lin_r = LinearPauliRotations(num_state_qubits=num_state_qubits,
                                         slope=mapped_slopes[i],
                                         offset=mapped_offsets[i],
                                         basis=basis)
            circuit.append(lin_r.to_gate().control(),
                           [comp_ancilla[0]] + qr_state[:] + [qr_target])

    return circuit
Esempio n. 10
0
def makeRecursiveCircuitUnqomp(n, m):
    # creates (recursively) a circuit to compute u_n where u_0 is the input on m bits, and u_(n+1) = f(u_n), returns an AncillaCircuit, without uncomputation
    f_gate = makesFGate(m, True)
    qr_input = QuantumRegister(m, "input")
    qr_output = QuantumRegister(m, "output")

    if n == 1:
        circuit = AncillaCircuit(qr_input, qr_output)
        circuit.append(f_gate, [*qr_input, *qr_output])
        return circuit

    qr_ancillas = AncillaRegister(m, "ancilla-" + str(n))
    circuit = AncillaCircuit(qr_input, qr_output, qr_ancillas)
    rec_circ = makeRecursiveCircuitUnqomp(n - 1, m)
    rec_gate = rec_circ.to_ancilla_gate()

    circuit.append(rec_gate, [*qr_input, *qr_ancillas])
    circuit.append(f_gate, [*qr_ancillas, *qr_output])

    return circuit
Esempio n. 11
0
def makesAdder(num_qubits):
    #[a, b]: b = a + b, a and b made of num_qubits each
    # returns an AncillaCircuit, without uncomputation
    def neg_mct_gate():
        neg_mct = AncillaCircuit(4)
        neg_mct.cx(1, 2)
        neg_mct.ccx(0, 2, 3)
        neg_mct.cx(1, 2)
        return neg_mct.to_ancilla_gate(True)

    def carry_gate():
        carry_circ = AncillaCircuit(4)
        (c0, a, b, c1) = (carry_circ.qubits[0], carry_circ.qubits[1],
                          carry_circ.qubits[2], carry_circ.qubits[3])
        carry_circ.ccx(a, b, c1)
        carry_circ.append(neg_mct_gate(), [c0, a, b, c1])
        return carry_circ.to_ancilla_gate()

    def sum_gate():
        sum_circ = AncillaCircuit(3)
        (c0, a, b) = (sum_circ.qubits[0], sum_circ.qubits[1],
                      sum_circ.qubits[2])
        sum_circ.cx(a, b)
        sum_circ.cx(c0, b)
        return sum_circ.to_ancilla_gate()

    a = QuantumRegister(num_qubits, name="a")
    b = QuantumRegister(num_qubits, name="b")
    c = AncillaRegister(num_qubits, name="c")

    circuit = AncillaCircuit(a, b, c)

    for i in range(num_qubits - 1):
        circuit.append(carry_gate(), [c[i], a[i], b[i], c[i + 1]])
        circuit.append(sum_gate(), [c[i], a[i], b[i]])
    circuit.append(sum_gate(),
                   [c[num_qubits - 1], a[num_qubits - 1], b[num_qubits - 1]])

    return circuit
Esempio n. 12
0
def makeWeightedAdderWOExtraCtrlsQb(num_state_qubits, weights):
    # Implementation using Unqomp but enforcing local uncomputation, uses less qubits, but is not fully modular, ancillas have to be taken care of manually
    def neg_mct_gate(negated_ctrls):
        #circuit.mcx([q_state, qr_sum[j], qr_carry[j - 1]], qr_carry[j], negated_ctrls = [1, 2])
        ctrls = QuantumRegister(3)
        anc = QuantumRegister(1)
        targ = QuantumRegister(1)
        neg_mct = QuantumCircuit(ctrls, anc, targ)  #[ctrl0...ctrl3, anc, targ]
        for i in negated_ctrls:
            neg_mct.x(ctrls[i])
        neg_mct.mcx(ctrls, targ, anc, mode='basic')
        for i in negated_ctrls:
            neg_mct.x(ctrls[i])
        return neg_mct.to_gate()

    num_sum_qubits = int(np.floor(np.log2(sum(weights))) +
                         1) if sum(weights) > 0 else 1
    # The number of sum qubits in the circuit
    num_carry_qubits = num_sum_qubits - 1
    # The number of carry qubits required to compute the sum.

    for i, weight in enumerate(weights):
        if not np.isclose(weight, np.round(weight)):
            raise ValueError('Non-integer weights are not supported!')
        weights[i] = np.round(weight)

    num_result_qubits = num_state_qubits + num_sum_qubits

    qr_state = QuantumRegister(num_state_qubits, name='state')
    qr_sum = QuantumRegister(num_sum_qubits, name='sum')
    qr_ctrl = QuantumRegister(1, name='ctrl')
    circuit = AncillaCircuit(qr_state, qr_sum, qr_ctrl)

    neg_mct_g = neg_mct_gate([1, 2])
    mct_g = neg_mct_gate([])

    circuit.addQfreeGate(neg_mct_g)
    circuit.addQfreeGate(mct_g)

    # loop over state qubits and corresponding weights
    for i, weight in enumerate(weights):
        # only act if non-trivial weight
        if np.isclose(weight, 0):
            continue

        # get state control qubit
        q_state = qr_state[i]

        # get bit representation of current weight
        weight_binary = '{0:b}'.format(int(weight)).rjust(num_sum_qubits,
                                                          '0')[::-1]
        #print("carry qb" + str(num_carry_qubits))
        qr_carry = circuit.new_ancilla_register(num_carry_qubits,
                                                name="anccarryite" + str(i))

        # loop over bits of current weight and add them to sum and carry registers
        for j, bit in enumerate(weight_binary):
            if bit == '1':
                if num_sum_qubits == 1:
                    circuit.cx(q_state, qr_sum[j])
                elif j == 0:
                    # compute (q_sum[0] + 1) into (q_sum[0], q_carry[0])
                    # - controlled by q_state[i]
                    circuit.ccx(q_state, qr_sum[j], qr_carry[j])
                    circuit.cx(q_state, qr_sum[j])
                elif j == num_sum_qubits - 1:
                    # compute (q_sum[j] + q_carry[j-1] + 1) into (q_sum[j])
                    # - controlled by q_state[i] / last qubit,
                    # no carry needed by construction
                    circuit.cx(q_state, qr_sum[j])
                    circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
                else:
                    # compute (q_sum[j] + q_carry[j-1] + 1) into (q_sum[j], q_carry[j])
                    # - controlled by q_state[i]
                    circuit.append(neg_mct_g, [
                        q_state, qr_sum[j], qr_carry[j - 1], qr_ctrl,
                        qr_carry[j]
                    ])
                    circuit.cx(q_state, qr_carry[j])
                    circuit.cx(q_state, qr_sum[j])
                    circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
            else:
                if num_sum_qubits == 1:
                    pass  # nothing to do, since nothing to add
                elif j == 0:
                    pass  # nothing to do, since nothing to add
                elif j == num_sum_qubits - 1:
                    # compute (q_sum[j] + q_carry[j-1]) into (q_sum[j])
                    # - controlled by q_state[i] / last qubit,
                    # no carry needed by construction
                    circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
                else:
                    # compute (q_sum[j] + q_carry[j-1]) into (q_sum[j], q_carry[j])
                    # - controlled by q_state[i]
                    circuit.append(mct_g, [
                        q_state, qr_sum[j], qr_carry[j - 1], qr_ctrl,
                        qr_carry[j]
                    ])
                    circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
    return circuit