Ejemplo n.º 1
0
    def __cNot(self, gate_info):
        """
        Creates an arbitrary sized controlled not gate between two arbitrary qbits.

        :param gate_info: (tuple(int, int)) Position in the circuit of the control qubit and the controlled qubit
        :return: (SparseMatrix) The cnot gate entangling the two qubits given.
        """
        qbit1, qbit2 = gate_info

        if qbit1 > qbit2:
            control_bit = np.abs(qbit2 - qbit1)
            controlled_bit = 0
        else:
            control_bit = 0
            controlled_bit = qbit2 - qbit1

        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(np.abs(qbit2 - qbit1) + 1)
        for i in range(1, dimension):
            if self.__bitactive(i, control_bit):
                col = self.__toggle(i, controlled_bit)
                elements.append(Sparse.MatrixElement(i, col, 1))
            else:
                elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 2
0
    def __ccNot(self, gate_info):
        """
        Creates a Sparsematrix representing the controlled-controlled-not (ccnot or Tiffoli) 
        gate for the given qubits. Can be applied to any exisiting qubits.

        :param gate_info: (tuple(int, int, int)) first, second qubit controlling the gate and the qubit controlled by the other two
        :return: (SparseMatrix)  Matrix representation of the gate
        """
        control1, control2, qbit3 = gate_info
        # Reset the values to range from 0 to maxval
        minval = min(control1, control2, qbit3)
        maxval = max(control1, control2, qbit3) - minval
        control1 = control1 - minval
        control2 = control2 - minval
        qbit3 = qbit3 - minval

        # Create elements and calculate dimensions
        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(maxval + 1)

        # For each possible bit check whether the control qubits are active
        for i in range(1, dimension):
            if self.__bitactive(i, control1) and self.__bitactive(i, control2):
                # if control qubits are active, calculate the new value and insert into matrix
                col = self.__toggle(i, qbit3)
                elements.append(Sparse.MatrixElement(i, col, 1))
            else:
                elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 3
0
    def __cP(self, gate_info):
        """
        Creates a controlled phase gate for the given qubits

        :param gate_info: (tuple(int, int, float)) The information supplied to the gate. Control qubits as ints, float as the phase.
        :return: (SparseMatrix) Representation of the cp gate
        """
        qbit1, qbit2, phi = gate_info

        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(np.abs(qbit2 - qbit1) + 1)
        for i in range(1, dimension):
            if self.__bitactive(i, qbit1) and self.__bitactive(i, qbit2):
                elements.append(Sparse.MatrixElement(i, i, np.exp(1j * phi)))
            else:
                elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 4
0
    def __cZ(self, gate_info):
        """
        Creates a controlled z gate given 2 qubits

        :param gate_info: (tuple(int, int)) The two gates to control the z
        :return: (SparseMatrix) Representation of the cz gate
        """
        qbit1, qbit2 = gate_info
        shift = min(qbit1, qbit2)
        qbit1 = qbit1 - shift
        qbit2 = qbit2 - shift

        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(np.abs(qbit2 - qbit1) + 1)
        for i in range(1, dimension):
            if self.__bitactive(i, qbit1) and self.__bitactive(i, qbit2):
                elements.append(Sparse.MatrixElement(i, i, -1))
            else:
                elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 5
0
    def __NCZ(self, gate_info):
        """
        Adds a z gate controlled by an arbitrary number of bits
    
        :param gate_info: (tuple(int, int, int...,)) Control qubits as ints, arbitrary number
        :return: (SparseMatrix) Matrix representatin of the gate
        """
        bits = np.array(gate_info)
        bits = bits - min(bits)

        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(max(bits) - min(bits) + 1)
        for i in range(1, dimension):
            active = True
            for bit in bits:
                if not self.__bitactive(i, bit):
                    active = False
                    break
            if active: elements.append(Sparse.MatrixElement(i, i, -1))
            else: elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 6
0
    def __NCP(self, gate_info):
        """
        Adds a phase gate controlled by an arbitrary number of bits
    
        :param gate_info: (tuple(int, int, int..., float)) Control qubits as ints, phase as a float.
        :return: (SparseMatrix) Matrix representation of gate.
        """
        bits = np.array(gate_info[:-1])
        bits = bits - min(bits)
        phi = gate_info[-1]

        elements = [Sparse.MatrixElement(0, 0, 1)]
        dimension = 2**(max(bits) - min(bits) + 1)
        for i in range(1, dimension):
            active = True
            for bit in bits:
                if not self.__bitactive(i, bit):
                    active = False
                    break
            if active:
                elements.append(Sparse.MatrixElement(i, i, np.exp(1j * phi)))
            else:
                elements.append(Sparse.MatrixElement(i, i, 1))
        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 7
0
    def makeMatrices(self):
        """
        Creates the matrices that will be applied to the wavevector
    
        :return: (array) list of np matrices that will be applied to the statevector
        """
        gates = np.array(self.gates, dtype=object).T

        bigmats = []
        for i, slot in enumerate(gates):
            bigmat = Sparse.SparseMatrix(1, [Sparse.MatrixElement(0, 0, 1)])
            for j in slot:
                if type(j) == tuple:
                    bigmat = self.__addLargeGate(j).tensorProduct(bigmat)
                elif j == 's':
                    continue
                else:
                    bigmat = Sparse.makeSparse(
                        self.singlegates[j]).tensorProduct(bigmat)
            bigmats.append(bigmat)

        return np.array(bigmats)
Ejemplo n.º 8
0
    def __Swap(self, gate_info):
        """
        Creates the matrix representing the swap operation between two qubits.

        :param gate_info: (tuple(int, int)) The two gates to be swapped.
        :return: (SparseMatrix) Matrix representation of the swap gate.
        """
        qbit1, qbit2 = gate_info
        shift = min(qbit1, qbit2)
        qbit1 = qbit1 - shift
        qbit2 = qbit2 - shift
        elements = []
        dimension = 2**(np.abs(qbit2 - qbit1) + 1)
        for i in range(0, dimension):
            col = i
            if (self.__bitactive(i, qbit1) and not self.__bitactive(i, qbit2)
                ) or (not self.__bitactive(i, qbit1)
                      and self.__bitactive(i, qbit2)):
                col = self.__toggle(self.__toggle(i, qbit1), qbit2)
            elements.append(Sparse.MatrixElement(i, col, 1))

        return Sparse.SparseMatrix(dimension, elements)
Ejemplo n.º 9
0
    def simulate2(self):
        """
        Applies the circuit to the initialized statevector without storing the operations

        :return: The register and any measurements made
        """
        gates = np.array(self.gates, dtype=object).T

        for i, slot in enumerate(gates):
            bigmat = Sparse.SparseMatrix(1, [Sparse.MatrixElement(0, 0, 1)])
            for j in slot:
                if type(j) == tuple:
                    bigmat = self.__addLargeGate(j).tensorProduct(bigmat)
                elif j == 's':
                    continue
                else:
                    bigmat = Sparse.makeSparse(
                        self.singlegates[j]).tensorProduct(bigmat)
            self.register.Statevec = bigmat.apply(self.register.Statevec)
            if i in self.measurements[0]:
                self.measurements[1].append(self.register.Statevec.Elements)

        return self.register, self.measurements
Ejemplo n.º 10
0
def Grover_Circuit(n_qubits, measured_bits, plot_results=True):
    """
    Constructs a circuit representing Grover's algorithm for a given number of qubits and
    bits that we are interested in. Plots measurements after each iteration of the algorithm.

    :param n_qubits: (int) Number of qubits in the circuit.
    :param measured_bits: (list) list of bits that we are interested in and want to increase the amplitude of.

    """
    grover_circuit = QuantumCircuit.QuantumCircuit('Grover', n_qubits)
    grover_circuit.addGate('h', [i for i in range(n_qubits)])
    repetitions = int(np.pi/4*np.sqrt(2**n_qubits)) - 1
    
    grover_circuit.addmeasure()
    # calculate oracle
    elements = []
    for i in range(2**n_qubits):
        if i in measured_bits:
            elements.append(Sparse.MatrixElement(i,i,-1))
        else: elements.append(Sparse.MatrixElement(i,i,1))
    oracle_gate = Sparse.SparseMatrix(2**n_qubits, elements) # Creates a sparseMatrix representation of the oracle
    #print(oracle_gate.makedense())
    
    #Add Oracle
    grover_circuit.addCustom(0, n_qubits-1, oracle_gate, 'oracle')
    
    #grover_circuit.addmeasure()
    #Add diffuser
    diffuser(grover_circuit)

    grover_circuit.addmeasure()
    # Repeat if necessary
    for i in range(repetitions):
        # Add Oracle
        grover_circuit.addCustom(0, n_qubits-1, oracle_gate, 'oracle')
        #Add diffuser
        diffuser(grover_circuit)
        grover_circuit.addmeasure()

    #print(np.array(grover_circuit.gates, dtype=object)[:,:6])

    #show results
    #print(grover_circuit.return_measurements())
    final_statevec, measurements = grover_circuit.simulate2()
    #for m in measurements[1]:
    #   print(m)
    
    if plot_results:
        # plots the results in a snazzy way
        figure, axis = plt.subplots(1, len(measurements[1]))
        for j, measurement in enumerate(measurements[1]):
            axis[j].bar([i for i in range(measurement.size)], measurement*np.conj(measurement))
            axis[j].set_ylim([0,1])
            axis[j].set_xlabel("State |N>", fontsize = '13')
            if j>0:
                axis[j].set_yticklabels("")
            #print((results[2][1][j]*np.conj(results[2][1][j])).sum())
        axis[0].set_ylabel("Probability", fontsize = '13')
        
        #figure.set_ylabel("Probability of Measuring State")
        figure.suptitle("Probability of measuring state N",fontweight='bold', fontsize='15')
        plt.show()
        
        print(grover_circuit)