示例#1
0
def count(circuit, a, b, step=1, do_qft=True, amount=1):
    '''
    Count function for k colours. Takes register a as control qubits. 
    Counts in register b 

    Parameters
    ----------
    circuit : QuantumCircuit
        Quantum circuit to be appended with counter.
    a : QuantumRegister
        Control register a.
    b : QuantumRegister
        Count register b.
    step : int
        the length of each individual sub-interval in register a.
    do_qft : bool (default: True)
        Whether to include the QFT and iQFT on reg b.
    amount : float (default: 1)
        Multiplication factor on addition (i.e. get b+amount*|a|).

    Returns
    -------
    circuit : QuantumCircuit
        Quantum circuit appended with counter

    '''

    # Constants
    an = len(a)
    bn = len(b)

    # QFT
    if do_qft:
        circuit.barrier()
        qft(circuit, b)
        circuit.barrier()

    # Core count sub blocks
    for (i, qubit) in enumerate(a[0:an:step]):
        cnincrement(circuit,
                    a[(i * step):(i + 1) * step],
                    b,
                    do_qft=False,
                    amount=amount)
        circuit.barrier() if do_qft else None

    # iQFT
    if do_qft:
        circuit.barrier()
        iqft(circuit, b)
        circuit.barrier()

    return circuit
示例#2
0
def cnincrement(circuit, c, q, do_qft=True, amount=1):
    """Performs +1 on the value of register q, controlled by register c

    Parameters
    ----------
    circuit : QuantumCircuit
        Quantum circuit to be appended with increment.
    q : QuantumRegister
        Register to be incremented.
    c : Qubit List
        Control qubits
    do_qft : bool (default: True)
        Whether to include the QFT and iQFT on reg b.
    amount : float (default: 1)
        Multiplication factor on addition (i.e. get b+amount*a).

    Returns
    -------
    circuit : QuantumCircuit
        Quantum circuit appended with increment.
    
    """

    # Constants
    n = len(q)
    nc = len(c)

    # Optional QFT
    if do_qft:
        circuit.barrier()
        qft(circuit, q)
        circuit.barrier()

    # Actual core (controlled) increm gates
    for (i, qubit) in enumerate(q):
        # qcs = QuantumCircuit(1)
        # qcs.rz(amount*pi/2**(n-i-1),0)
        # ncrz = qcs.to_gate().control(nc)
        # circuit.append(ncrz, [*c, qubit])
        ncp = PhaseGate(amount * pi / 2**(n - i - 1)).control(nc)
        circuit.append(ncp, [*c, qubit])

    # Optional iQFT
    if do_qft:
        circuit.barrier()
        iqft(circuit, q)
        circuit.barrier()

    return circuit
示例#3
0
def increment(circuit, q, do_qft=True, amount=1):
    """Performs +1 on the value of register q

    Parameters
    ----------
    circuit : QuantumCircuit
        Quantum circuit to be appended with increment.
    q : QuantumRegister
        Register to be incremented.
    do_qft : bool (default: True)
        Whether to include the QFT and iQFT on reg b.
    amount : float (default: 1)
        Multiplication factor on addition (i.e. get b+amount*a).

    Returns
    -------
    circuit : QuantumCircuit
        Quantum circuit appended with increment.
    
    """

    # Constants
    n = len(q)

    # Optional QFT
    if do_qft:
        qft(circuit, q)

    # Actual increm core gates
    for (i, qubit) in enumerate(q):
        circuit.rz(amount * pi / 2**(n - 1 - i), qubit)

    # Optional iQFT
    if do_qft:
        iqft(circuit, q)

    return circuit
def build_mastermind_b_circuit(circuit, q, b, s, do_inverse=False):
    '''
    Counts b_s(q): the number of correct colours in query q (compared to s).

    Parameters
    ----------
    circuit : QuantumCircuit
        Quantum circuit to perform counting on.
    q : QuantumRegister, length n*ceil(log(k))
        Query register.
    b : QuantumRegister, length ceil(log(n))+1
        Register which stores amount of correct colours.
    s : Int list, length n
        Secret string.
    do_inverse : bool (default: False)
        Whether to perform the inverse of the circuit.

    Returns
    -------
    circuit : QuantumCircuit
        Quantum circuit appended with b-oracle.
    
    '''

    # Extract basic system parameters (n = # of pins, k = # of colours, logk = # of bits for k)
    n = len(s)
    logk = len(q) // n

    # how often which colour occurs in the list
    secret_sequence_colours_amount = [
        list(s).count(i) for i in range(2**logk)
    ]  # rather k, but that's annoying

    qft(circuit, b)
    for (c, nc) in enumerate(secret_sequence_colours_amount):
        if nc != 0:
            comp_list = [1] + (nc - 1) * [0]
            for nc_q in range(nc + 1, n + 1):
                n_perm = [math.comb(nc_q, i) for i in range(1, nc_q)]
                res = sum([a * b for a, b in zip(n_perm, comp_list)])
                comp_list += [nc - res]
            binary_list = [bin(c)[2:].zfill(logk)] * n
            binary_to_x_gates(circuit, q, binary_list)
            for i in range(n):
                if not do_inverse:
                    cnincrement(circuit,
                                q[(logk * i):(logk * (i + 1))],
                                b,
                                do_qft=False)
                else:
                    cndecrement(circuit,
                                q[(logk * i):(logk * (i + 1))],
                                b,
                                do_qft=False)
            for i in range(n - nc):
                j = i + nc
                comp = comp_list[j]
                for combination in list(combinations(range(n), j + 1)):
                    qtemptemp = [
                        q[(logk * l):(logk * (l + 1))] for l in combination
                    ]
                    qtemp = []
                    for qlist in qtemptemp:
                        qtemp += qlist
                    if comp != 0:
                        if not do_inverse:
                            cnincrement(circuit,
                                        qtemp,
                                        b,
                                        amount=comp,
                                        do_qft=False)
                        else:
                            cndecrement(circuit,
                                        qtemp,
                                        b,
                                        amount=comp,
                                        do_qft=False)
            binary_to_x_gates(circuit, q, binary_list)
    iqft(circuit, b)

    return circuit
def build_mastermind_b_circuit_v2(circuit, q, b, c, d, s, do_inverse=False):
    '''
    Counts b_s(q): the number of correct colours in query q (compared to s).

    Parameters
    ----------
    circuit : QuantumCircuit
        Quantum circuit to perform counting on.
    q : QuantumRegister, length n*ceil(log(k))
        Query register.
    b : QuantumRegister, length ceil(log(n))+1
        Register which stores amount of correct colours.
    c : QuantumRegister, length ceil(log(n))+1
        Ancilla register which stores the differences abs(n_s(q)-n_c(q)).
    d : QuantumRegister, length 1
        Ancilla register which stores the sign sgn(n_s(q)-n_c(q)).
    s : Int list, length n
        Secret string.
    do_inverse : bool (default: False)
        Whether to perform the inverse of the circuit.

    Returns
    -------
    circuit : QuantumCircuit
        Quantum circuit appended with b-oracle.
    
    '''

    # Extract basic system parameters (n = # of pins, k = # of colours, logk = # of bits for k)
    n = len(s)
    logk = len(q) // n

    # How often which colour occurs in the list
    secret_sequence_colours_amount = [
        list(s).count(i) for i in range(2**logk)
    ]  # rather k, but that's annoying

    # Check if valid secret string
    if sum(secret_sequence_colours_amount) != n:
        raise ValueError("Secret string contains illegal values")

    # Put QFT on reg b outside loop for efficiency
    qft(circuit, b)

    # Add n to reg b (equivalent to adding n_c for each c; more efficient)
    increment(circuit, b, amount=n, do_qft=False)

    # Flip sign bit d
    circuit.x(d)
    # Loop over colours (and how often they're used)
    for (clr, nc) in enumerate(secret_sequence_colours_amount):
        # Only start counting process is colour is used at all
        if nc != 0:

            # Write colour clr in n*binary...
            binary_list = [bin(clr)[2:].zfill(logk)] * n
            # ... to CNOT with query (so if matches, then |11>)
            binary_to_x_gates(circuit, q, binary_list)

            if not do_inverse:

                # Add n_c(s) to reg c...
                increment(circuit, c, amount=nc, do_qft=True)

                # ... and subtract n_c(q) from that value (with sign bit d)
                icount(circuit, q, [*c, d], step=logk, do_qft=True)

                # If sign bit d has not flipped (i.e. is True, i.e n_c(q)<n_c(s)):
                #  subtract difference n_c(s)-n_c(q)
                csub(circuit, a=c, b=b, c=d, do_qft=False)

                # Undo step 1 & 2
                count(circuit, q, [*c, d], step=logk, do_qft=True)
                decrement(circuit, c, amount=nc, do_qft=True)

            else:

                # Inverse of steps above
                increment(circuit, c, amount=nc, do_qft=True)
                icount(circuit, q, [*c, d], step=logk, do_qft=True)
                cadd(circuit, a=c, b=b, c=d, do_qft=False)
                decrement(circuit, b, amount=nc, do_qft=False)
                count(circuit, q, [*c, d], step=logk, do_qft=True)
                decrement(circuit, c, amount=nc, do_qft=True)

            # Undo query CNOT
            binary_to_x_gates(circuit, q, binary_list)
            circuit.barrier()

    # Flip sign bit d
    circuit.x(d)

    # Finish sum procedure with iQFT on reg b
    iqft(circuit, b)

    return circuit