Example #1
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
Example #2
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
Example #3
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
Example #4
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
Example #5
0
def makeWeightedAdder(num_state_qubits, weights):
    # Straightforward implementation using Unqomp, uses less gate but more qubits
    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')
    circuit = AncillaCircuit(qr_state, qr_sum)
    #print(num_state_qubits)
    #print(num_sum_qubits)

    # 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.mcx([q_state, qr_sum[j], qr_carry[j - 1]],
                                qr_carry[j],
                                negated_ctrls=[1, 2])
                    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.mcx([q_state, qr_sum[j], qr_carry[j - 1]],
                                qr_carry[j])
                    circuit.ccx(q_state, qr_carry[j - 1], qr_sum[j])
    return circuit
Example #6
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