Exemplo n.º 1
0
def change_of_basis_matrix_to_quil(qc: QuantumComputer, qubits: Sequence[int],
                                   change_of_basis: np.ndarray) -> Program:
    """
    Helper to return a native quil program for the given qc to implement the change_of_basis matrix.

    :param qc: Quantum Computer that will need to use the change of basis
    :param qubits: the qubits the program should act on
    :param change_of_basis: a unitary matrix acting on len(qubits) many qubits
    :return: a native quil program that implements change_of_basis on the qubits of qc.
    """
    prog = Program()
    # ensure the program is compiled onto the proper qubits
    prog += Pragma('INITIAL_REWIRING', ['"NAIVE"'])
    g_definition = DefGate("COB", change_of_basis)
    # get the gate constructor
    COB = g_definition.get_constructor()
    # add definition to program
    prog += g_definition
    # add gate to program
    prog += COB(*qubits)
    # compile to native quil
    nquil = qc.compiler.quil_to_native_quil(prog)

    # strip the program to only what we need, i.e. the gates themselves.
    only_gates = Program([inst for inst in nquil if isinstance(inst, Gate)])

    return only_gates
Exemplo n.º 2
0
    def __produce_u_f_gate(self):
        '''
        Solve a linear system of equations using
        the mapping between the input and the output
        to get the U_f matrix.

        Produce the gate to be used in the circuit using
        the matrix.
        '''
        bit_strings = self.__generate_bit_strings(self.n + 1)
        xs = list()
        bs = list()
        for bit_string in bit_strings:
            xs.append(self.__get_tensor(bit_string))
            modified_bit_string = self.__modify_bit_string(bit_string)
            bs.append(self.__get_tensor(modified_bit_string))

        X = np.hstack(tuple(xs))
        B = np.hstack(tuple(bs))

        A = np.linalg.solve(np.linalg.inv(B), np.linalg.inv(X))
        self.__u_f = np.array(A)
        print(self.__u_f)

        self.__u_f_definition = DefGate("U_f", self.__u_f)
        self.__U_f = self.__u_f_definition.get_constructor()
Exemplo n.º 3
0
def qubit_unitary(par, *wires):
    r"""Define a pyQuil custom unitary quantum operation.

    Args:
        par (array): a :math:`2^N\times 2^N` unitary matrix
            representing a custom quantum operation.
        wires (list): list of wires to prepare the basis state on

    Returns:
        list: list of PauliX matrix operators acting on each wire
    """
    if par.shape[0] != par.shape[1]:
        raise ValueError("Qubit unitary must be a square matrix.")

    if not np.allclose(par @ par.conj().T, np.identity(par.shape[0])):
        raise ValueError("Qubit unitary matrix must be unitary.")

    if par.shape != tuple([2**len(wires)] * 2):
        raise ValueError(
            "Qubit unitary matrix must be 2^Nx2^N, where N is the number of wires."
        )

    # Get the Quil definition for the new gate
    gate_definition = DefGate("U_{}".format(str(uuid.uuid4())[:8]), par)
    # Get the gate constructor
    gate_constructor = gate_definition.get_constructor()
    return [gate_definition, gate_constructor(*wires)]
Exemplo n.º 4
0
    def _apply_zf(self, qubits):
        """
        Define Z_f gate (if not defined) and applies it to qubits.

        Parameters
        ----------
        qubits : [int]
            Qubits to apply Z_f to.

        Returns
        ----------
        Z_f : Gate
            Z_f gate applied to qubits

        """

        if self.zf_definition is None:
            # Initializes Z_f as a 2^n by 2^n matrix of zeros
            Z_f = np.eye(2**self.n, dtype=int)

            # Apply definition of Z_f = (-1)^{f(x)} to construct matrix
            for x in range(2**self.n):
                Z_f[x][x] = (-1)**self.f(x)

            # Multiply by -1 to account for leading minus in G
            Z_f *= -1

            self.zf_definition = DefGate("Z_f", Z_f)
            self.p += self.zf_definition

        Z_f = self.zf_definition.get_constructor()
        return Z_f(*qubits)
Exemplo n.º 5
0
    def _apply_uf(self, qubits):
        """
        Define U_f gate (if not defined) that encodes oracle function f and applies it to qubits.

        Parameters
        -------
        qubits : [int]
            Qubits to apply U_f to.

        Returns
        -------
        U_f : Gate
            Z_f gate applied to qubits.

        """

        if self.uf_definition is None:
            # Initializes U_f as a 2^(n+1) by 2^(n+1) matrix of zeros
            U_f = np.zeros((2 ** (self.n + 1),) * 2, dtype=int)

            # Apply definition of U_f = |x>|b + f(x)> to construct matrix
            for x in range(2 ** self.n):
                for b in [0, 1]:
                    row = (x << 1) ^ b
                    col = (x << 1) ^ (self.f(x) ^ b)
                    U_f[row][col] = 1

            self.uf_definition = DefGate("U_f", U_f)
            self.p += self.uf_definition

        U_f = self.uf_definition.get_constructor()
        return U_f(*qubits)
Exemplo n.º 6
0
    def _apply_z0(self, qubits):
        """
        Defines Z_0 gate (if not defined) and applies it to qubits.

        Parameters
        ----------
        qubits : [int]
            Qubits to apply Z_0 to.

        Returns
        ----------
        Z_0 : Gate
            Z_0 gate applied to qubits

        """

        if self.z0_definition is None:
            # Create Z_0 as identity, except with -1 in top-left corner
            Z_0 = np.eye(2**self.n)
            Z_0[0][0] = -1

            self.z0_definition = DefGate("Z_0", Z_0)
            self.p += self.z0_definition

        Z_0 = self.z0_definition.get_constructor()
        return Z_0(*qubits)
Exemplo n.º 7
0
def orig_encode(qubit):
    qubit_a = 4
    qubit_b = 3
    qubit_c = 1
    qubit_d = 0

    # qubit_a = QubitPlaceholder()
    # qubit_b = QubitPlaceholder()
    # qubit_c = QubitPlaceholder()
    # qubit_d = QubitPlaceholder()

    pi_rot = np.array([[-1.0, 0], [0, -1.0]])
    pi_rot_def = DefGate("PI-ROT", pi_rot)
    PI_ROT = pi_rot_def.get_constructor()

    code_register = [qubit_a, qubit_b, qubit, qubit_c, qubit_d]

    pq = Program(H(qubit_a), H(qubit_b), H(qubit_c))
    pq += pi_rot_def
    pq += PI_ROT(qubit_d).controlled(qubit_b).controlled(qubit).controlled(
        qubit_c)
    pq += [X(qubit_b), X(qubit_c)]
    pq += PI_ROT(qubit_d).controlled(qubit_b).controlled(qubit).controlled(
        qubit_c)
    pq += [X(qubit_b), X(qubit_c)]
    pq += CNOT(qubit, qubit_d)
    pq += CNOT(qubit_a, qubit)
    pq += CNOT(qubit_a, qubit_d)
    pq += CNOT(qubit_c, qubit)
    pq += CNOT(qubit_b, qubit_d)
    pq += PI_ROT(qubit).controlled(qubit_c).controlled(qubit_d)

    return pq, code_register
Exemplo n.º 8
0
    def _apply_uf(self, qubits):
        """
        Creates a U_f gate that encodes oracle function f and applies it to qubits.

        Parameters
        ----------
        qubits : [int]
            Qubits to apply U_f to.

        Returns
        ----------
        [uf_definition, U_f] : [DefGate, Callable]
            Quil definition for U_f and the gate.

        """

        # Initializes U_f as a 2^(2n) by 2^(2n) matrix of zeros
        U_f = np.zeros((2**(self.n * 2), ) * 2, dtype=int)

        # Apply definition of U_f = |x>|b + f(x)> to construct matrix
        for x in range(2**self.n):
            # Number of helper bits is equal to number of qubits
            for b in range(2**self.n):
                row = (x << self.n) ^ b
                col = (x << self.n) ^ (self.f(x) ^ b)
                U_f[row][col] = 1

        uf_definition = DefGate("U_f", U_f)
        gate = uf_definition.get_constructor()
        return [uf_definition, gate(*qubits)]
Exemplo n.º 9
0
	def get_circuit(self, f, n_qubits):

		# construct oracle and define its gate constructor
		oracle = self.getOracle(f, n_qubits)
		oracle_definition = DefGate("ORACLE", oracle)
		ORACLE = oracle_definition.get_constructor()

		# make circuit
		p = Program()

		# apply the first hadamard to all qubits
		for i in range(n_qubits):
			p += H(i)

		# NOT ancilla qubit then apply hadamard
		p += X(n_qubits)
		p += H(n_qubits)

		# apply oracle to all qubits
		p += oracle_definition
		p += ORACLE(*range(n_qubits+1))

		# apply hadamard to computational qubits
		for i in range(n_qubits):
			p += H(i)

		return p
Exemplo n.º 10
0
 def __produce_z_0_gate(self):
     '''
     Produce matrix and gate for Z_0
     '''
     z_0 = np.identity(2**n)
     z_0[0][0] = -z_0[0][0]
     self.__z_0_definition = DefGate("Z_0", z_0)
     self.__Z_0 = self.__z_0_definition.get_constructor()
Exemplo n.º 11
0
 def __produce_negative_gate(self):
     '''
     Produce matrix and gate for changing
     the coefficient of the set of qubits.
     '''
     negative = -np.identity(2**n)
     self.__negative_definition = DefGate("NEGATIVE", negative)
     self.__NEGATIVE = self.__negative_definition.get_constructor()
Exemplo n.º 12
0
def qc_program(n, m, reload, verbose):
    # Simon's algorithm uses (n - 1) * 4m iterations
    t = (n - 1) * (4 * m)
    SAVEDIR = 'uf/simon/'
    SPATH = 's_dict.npy'

    U_f_def = DefGate('U_f', getUf(n, reload))
    U_f = U_f_def.get_constructor()

    if os.path.exists(SAVEDIR + SPATH):
        s = np.load(SAVEDIR + SPATH, allow_pickle=True).item()[n]
    else:
        s = None

    qc = get_qc(f'{str(2*n)}q-qvm')
    qc.compiler.client.timeout = 1000000

    p = Program()
    p += U_f_def
    p += (H(i) for i in range(n))
    p += U_f(*(tuple(range(2 * n))))
    p += (H(i) for i in range(n))

    result = qc.run_and_measure(p, trials=t)
    if verbose:
        print('====================================')
        print('Measured Qubit State Across Trials:')
        for i in range(n):
            print(f'    {result[i]}')
        print('====================================\n')

    if verbose:
        print('====================================')
        print('Measured y values:')

    for i in range(4 * m):
        if verbose:
            print(f'    Trial {i+1}:')

        ys = []
        for j in range((n - 1) * i, (n - 1) * (i + 1)):
            measured = [result[q][j] for q in range(n)]
            y = "".join(str(b) for b in measured)
            ys.append(measured)
            if verbose:
                print(f'        y_{j - (n-1)*i} = {y}')
        if check_lin_indep(ys):
            if verbose:
                print(
                    f'Found linearly independent ys!\nChecking if they solve to s correctly...'
                )
                print('====================================\n')
            return check_valid(ys, s)

    if verbose:
        print('====================================\n')

    return None
Exemplo n.º 13
0
def Uf(uf_matrix):
    """
    Returns the U_f gate for a given function f.
    :param f: matrix repr
    :return: the gate representation of f
    """
    uf_definition = DefGate("UF-GATE", uf_matrix)
    UF_GATE = uf_definition.get_constructor()
    return uf_definition, UF_GATE
Exemplo n.º 14
0
def simulate_controlled_y():
    y = np.array([[0, -1j], [1j, 0]])
    controlled_y_definition = DefGate("CONTROLLED-Y", controlled(y))
    CONTROLLED_Y = controlled_y_definition.get_constructor()

    p = Program(controlled_y_definition)
    p += NOT(0)
    p += CONTROLLED_Y(0, 1)
    print(WavefunctionSimulator().wavefunction(p))
Exemplo n.º 15
0
def makeControlGate(mat2D, gateName):
    u00 = mat2D[0][0]
    u01 = mat2D[0][1]
    u10 = mat2D[1][0]
    u11 = mat2D[1][1]
    cgatemat = array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, u00, u01],
                      [0, 0, u10, u11]])
    gatedef = DefGate(gateName, cgatemat)

    return gatedef, gatedef.get_constructor()
 def __produce_z_f_gate(self):
     z_f = np.identity(2**n)
     bit_strings = self.__generate_bit_strings(self.n)
     for bit_string in bit_strings:
         output = f(bit_string)
         if output == 1:
             i = bit_strings.index(bit_string)
     #i = np.random.randint(2**n)
     z_f[i][i] = -z_f[i][i]
     self.__z_f_definition = DefGate("Z_f", z_f)
     self.__Z_f = self.__z_f_definition.get_constructor()
Exemplo n.º 17
0
def _naive_program_generator(qc: QuantumComputer, qubits: Sequence[int],
                             permutations: np.ndarray,
                             gates: np.ndarray) -> Program:
    """
    Naively generates a native quil program to implement the circuit which is comprised of the given
    permutations and gates.

    :param qc: the quantum resource that will implement the PyQuil program for each model circuit
    :param qubits: the qubits available for the implementation of the circuit. This naive
        implementation simply takes the first depth-many available qubits.
    :param permutations: array of depth-many arrays of size n_qubits indicating a qubit permutation
    :param gates: a depth by depth//2 array of matrices representing the 2q gates at each layer.
        The first row of matrices is the earliest-time layer of 2q gates applied.
    :return: a PyQuil program in native_quil instructions that implements the circuit represented by
        the input permutations and gates. Note that the qubits are measured in the proper order
        such that the results may be directly compared to the simulated heavy hitters from
        collect_heavy_outputs.
    """
    num_measure_qubits = len(permutations[0])
    # at present, naively select the minimum number of qubits to run on
    qubits = qubits[:num_measure_qubits]

    # create a simple program that uses the compiler to directly generate 2q gates from the matrices
    prog = Program()
    for layer_idx, (perm, layer) in enumerate(zip(permutations, gates)):
        for gate_idx, gate in enumerate(layer):
            # get the Quil definition for the new gate
            g_definition = DefGate(
                "LYR" + str(layer_idx) + "_RAND" + str(gate_idx), gate)
            # get the gate constructor
            G = g_definition.get_constructor()
            # add definition to program
            prog += g_definition
            # add gate to program, acting on properly permuted qubits
            prog += G(int(qubits[perm[gate_idx]]),
                      int(qubits[perm[gate_idx + 1]]))

    ro = prog.declare("ro", "BIT", len(qubits))
    for idx, qubit in enumerate(qubits):
        prog.measure(qubit, ro[idx])

    native_quil = qc.compiler.quil_to_native_quil(prog)

    if not set(native_quil.get_qubits()).issubset(set(qubits)):
        raise ValueError(
            "naive_program_generator could not generate program using only the "
            "qubits supplied. Please provide your own program_generator if you wish "
            "to use only the qubits specified.")

    return native_quil
Exemplo n.º 18
0
 def __produce_z_f_gate(self):
     '''
     Produce matrix and gate for Z_f
     using the mapping between the input and output.
     '''
     z_f = np.identity(2**n)
     bit_strings = self.__generate_bit_strings(self.n)
     for bit_string in bit_strings:
         output = f(bit_string)
         if output == 1:
             i = bit_strings.index(bit_string)
     #i = np.random.randint(2**n)
     z_f[i][i] = -z_f[i][i]
     self.__z_f_definition = DefGate("Z_f", z_f)
     self.__Z_f = self.__z_f_definition.get_constructor()
Exemplo n.º 19
0
def create_Np1_bit_CZ(N: int):
	my_mat = np.identity(2 ** (N + 1))

	# middle = ((2 ** N) // 2) - 1
	last = 2 ** (N + 1) - 1

	# my_mat[middle, middle] = 0 #Middle row, middle column 11..0 
	# my_mat[middle, last] = 1 # Bottom row, middle column 11..0 -> 11..1

	my_mat[last, last] = 0
	my_mat[last - 1, last - 1] = 0
	my_mat[last - 1, last] = 1
	my_mat[last, last - 1] = 1

	Np1_bit_CZ = DefGate("Nbit_CZ", my_mat)
	return Np1_bit_CZ, Np1_bit_CZ.get_constructor()
Exemplo n.º 20
0
def qubit_unitary(par, *wires):
    r"""Define a pyQuil custom unitary quantum operation.

    Args:
        par (array): a :math:`2^N\times 2^N` unitary matrix
            representing a custom quantum operation.
        wires (list): list of wires to prepare the basis state on

    Returns:
        list: list of PauliX matrix operators acting on each wire
    """
    # Get the Quil definition for the new gate
    gate_definition = DefGate("U_{}".format(str(uuid.uuid4())[:8]), par)
    # Get the gate constructor
    gate_constructor = gate_definition.get_constructor()
    return [gate_definition, gate_constructor(*wires)]
Exemplo n.º 21
0
	def makeTheCircuit(self, bitmap):
		#Make U_f from what we've been given
		simCircuit = Program()

		#Apply Hadamard's to the computational (e.g. first n) qubits
		for i in range(self.n_compQubs):
			simCircuit+=H(i)
		#Apply U_f to the circuit (all qubits)
		oracle = self.makeU_f(bitmap)
		oracle_definition = DefGate("ORACLE", oracle)
		ORACLE = oracle_definition.get_constructor()
		simCircuit += oracle_definition
		simCircuit += ORACLE(*reversed(range(self.n_compQubs*2)))
		#Apply a second Hadamard to the first n qubits (again)
		for i in range(self.n_compQubs):
			simCircuit+=H(i)
		return simCircuit
    def define_extra_gates(self, qubit_program):
        ''' Defines quarter & eighth turn gates for the qubit program '''
        # Gates to be used in calculate method
        global POS_SQRT_X, NEG_SQRT_X
        global POS_SQRT_Y, NEG_SQRT_Y
        global POS_SQRT_Z, NEG_SQRT_Z
        global POS_FTRT_X, NEG_FTRT_X
        global POS_FTRT_Y, NEG_FTRT_Y
        global POS_FTRT_Z, NEG_FTRT_Z

        # Definition of the unitary matrices for x, y & z pauli gates based on powers
        g = lambda p: cmath.exp(-1j*p*np.pi/-2)
        c = lambda p: math.cos(p*np.pi/2)
        s = lambda p: math.sin(p*np.pi/2)
        x_pow_gate = lambda p: np.array([[g(p)*c(p), -1j*g(p)*s(p)], [-1j*g(p)*s(p), g(p)*c(p)]])
        y_pow_gate = lambda p: np.array([[g(p)*c(p), -g(p)*s(p)], [g(p)*s(p), g(p)*c(p)]])
        z_pow_gate = lambda p: np.array([[1, 0],[0, g(2*p)]])

        # Definition of the different dimensions and powers, all combinations
        dims = ['X', 'Y', 'Z']
        powers = {"POS-SQRT": 0.5, "NEG-SQRT": -0.5, "POS-FTRT": 0.25, "NEG-FTRT": -0.25}
        constructors = {}
        for dim in dims:
            for power in powers:
                gate_name = power + "-" + dim
                # Get the unitary matrix for that dimension to the specific power
                if dim in 'X': matrix = x_pow_gate(powers[power])
                elif dim in 'Y': matrix = y_pow_gate(powers[power])
                else: matrix = z_pow_gate(powers[power])
                # Get the Quil definition for the new gate
                gate_def = DefGate(gate_name, matrix)
                # Get the gate constructor
                constructors[gate_name] = gate_def.get_constructor()
                # Then we can use the new gate
                qubit_program += gate_def

        # Assign gate constructurs
        POS_SQRT_X, NEG_SQRT_X = constructors["POS-SQRT-X"], constructors["NEG-SQRT-X"]
        POS_SQRT_Y, NEG_SQRT_Y = constructors["POS-SQRT-Y"], constructors["NEG-SQRT-Y"]
        POS_SQRT_Z, NEG_SQRT_Z = constructors["POS-SQRT-Z"], constructors["NEG-SQRT-Z"]

        POS_FTRT_X, NEG_FTRT_X = constructors["POS-FTRT-X"], constructors["NEG-FTRT-X"]
        POS_FTRT_Y, NEG_FTRT_Y = constructors["POS-FTRT-Y"], constructors["NEG-FTRT-Y"]
        POS_FTRT_Z, NEG_FTRT_Z = constructors["POS-FTRT-Z"], constructors["NEG-FTRT-Z"]

        return qubit_program
 def __produce_u_f_gate(self):
     bit_strings = self.__generate_bit_strings(self.n+1)
     xs = list()
     bs = list()
     for bit_string in bit_strings:
         xs.append(self.__get_tensor(bit_string))
         modified_bit_string = self.__modify_bit_string(bit_string)
         bs.append(self.__get_tensor(modified_bit_string))
     
     X = np.hstack(tuple(xs))
     B = np.hstack(tuple(bs))
     
     A = np.linalg.solve(np.linalg.inv(B), np.linalg.inv(X))
     self.__u_f = np.array(A)
     print(self.__u_f)
     
     self.__u_f_definition = DefGate("U_f", self.__u_f)
     self.__U_f = self.__u_f_definition.get_constructor()
Exemplo n.º 24
0
    def prep_circuit_program(self, params):

        prog = Program()
        for i in range(len(gates)):
            q1 = gates[i][0]
            q2 = gates[i][1]
            index = i*16
            unitary = self.two_qubit_unitary(params[index:index+16])
            gate_definition = DefGate("GATE"+str(q1)+"-"+str(q2), unitary)
            gate = gate_definition.get_constructor()
            prog.inst(gate_definition, gate(q1, q2))

        # index = 20*len(gates)
        # unitary = self.single_qubit_unitary(params[index:index+6], self.n - 1)
        # gate_definition = DefGate("GATE15", unitary)
        # gate = gate_definition.get_constructor()
        # prog.inst(gate_definition, gate(self.n-1))

        return prog
Exemplo n.º 25
0
def simon_program(U_f, n):
    p = Program()

    # apply Hadamard to n qubits
    for i in range(n):
        p += H(i)

# define the U_f gate based on the unitary matrix returned by get_U_f
    U_f_def = DefGate("U_f", U_f)
    U_f_GATE = U_f_def.get_constructor()
    p += U_f_def
    p += U_f_GATE(*range(2 * n))

    # apply Hadamard to all input qubits
    for k in range(n):
        p += H(k)

# print(p)
    return p
    def _compile_unitary(self, unitary):
        """Compiles the unitary to a program.

        Args:
            unitary : numpy.ndarray
                Unitary matrix to compile.

        Returns:
            A pyquil.Program with gates that build up the unitary.
        """
        # Define the gate from the unitary
        gate = DefGate("U", unitary)

        # Get the constructor
        U_gate = gate.get_constructor()

        # Get the qubit indices
        qubit_indices = self.device_qubits  # NOTE: Brian changed to work with chip indices not range(self.num_qubits)
        # Return the program
        return Program(gate, U_gate(*tuple(qubit_indices)))
Exemplo n.º 27
0
def dj_program(U_f, n):
    p = Program()

    # invert the helper qubit to make it 1
    p += X(n)
    # apply Hadamard to all input qubits and helper qubit
    for i in range(n + 1):
        p += H(i)

    # define the U_f gate based on the unitary matrix returned by get_U_f
    U_f_def = DefGate("U_f", U_f)
    U_f_GATE = U_f_def.get_constructor()
    p += U_f_def
    p += U_f_GATE(*range(n + 1))

    # apply Hadamard to all input qubits
    for i in range(n):
        p += H(i)

    # print(p)
    return p
Exemplo n.º 28
0
    def get_circuit(self, f, n_qubits):
        """Creates the DJ circuit for this function f.

		Parameters
		----------
		f : f : {0,1}^n -> {0,1}
			Takes an n-bit array and outputs 1 bit.
			Either constant or balanced.

		Returns
		-------
		1 if f is constant
		0 if f is balanced
		"""

        # construct oracle and define its gate constructor
        oracle = self.getOracle(f, n_qubits)
        oracle_definition = DefGate("ORACLE", oracle)
        ORACLE = oracle_definition.get_constructor()

        # make circuit
        p = Program()

        # apply the first hadamard to all qubits
        for i in range(n_qubits):
            p += H(i)

        # NOT ancilla qubit then apply hadamard
        p += X(n_qubits)
        p += H(n_qubits)

        # apply oracle to all qubits
        p += oracle_definition
        p += ORACLE(*range(n_qubits + 1))

        # apply hadamard to computational qubits
        for i in range(n_qubits):
            p += H(i)

        return p
Exemplo n.º 29
0
def single_shot_grovers(input_bits):
    n = round(math.log2(len(input_bits)))
    if 2**n != len(input_bits):
        raise Exception(f"could not logify ${input_bits}")

    # Construct gates for operating our function, and Grover diffusion
    bit_picker_matrix = np.diag([1 - 2 * bit for bit in input_bits])
    bit_picker_definition = DefGate("BIT-PICKER", bit_picker_matrix)
    BIT_PICKER = bit_picker_definition.get_constructor()

    diffusion_matrix = diffusion(len(input_bits))
    diffusion_definition = DefGate("DIFFUSION", diffusion_matrix)
    DIFFUSION = diffusion_definition.get_constructor()

    # Wire up the program
    qvm = get_qvm(n)
    p = Program()
    p += bit_picker_definition
    p += diffusion_definition

    # Superposition
    for i in range(n):
        p += H(i)

    p += BIT_PICKER(*range(n))
    p += DIFFUSION(*range(n))

    ro = p.declare("ro", "BIT", n)
    for i in range(n):
        p += MEASURE(i, ro[i])

    result = qvm.run(p)
    return number_from_binary(result[0])
Exemplo n.º 30
0
    def get_circuit(self, f, n_qubits):

        # make oracle gate Z_f
        oracle = self.getOracle(f, n_qubits)
        oracle_definition = DefGate('ORACLE', oracle)
        ORACLE = oracle_definition.get_constructor()

        # make helper gate Z_0
        helper = self.getHelper(n_qubits)
        helper_definition = DefGate('HELPER', helper)
        HELPER = helper_definition.get_constructor()

        # make flipper gate -I
        flipper = self.getFlipper(n_qubits)
        flipper_definition = DefGate('FLIPPER', flipper)
        FLIPPER = flipper_definition.get_constructor()

        # make circuit
        p = Program()

        # apply the first hadamard to all qubits
        for i in range(n_qubits):
            p += H(i)

        # add oracle and helper definitions
        p += oracle_definition
        p += helper_definition
        p += flipper_definition

        # apply oracle and diffuser designated amount of times
        NUM_ITERATIONS = int(math.sqrt(2**n_qubits) * math.pi / 4)
        for _ in range(NUM_ITERATIONS):

            # apply oracle
            p += ORACLE(*range(n_qubits))

            # apply diffuser
            for i in range(n_qubits):
                p += H(i)
            p += HELPER(*range(n_qubits))
            for i in range(n_qubits):
                p += H(i)
            p += FLIPPER(*range(n_qubits))

        return p