def apply_swap(self, wire_index1, wire_index2):
        '''
        Method applying the swap gate to the quantum state \n
        @param wire_index1: Integer indicating location of gate \n
        @param wire_index2: Integer indicating location of gate \n
        @return: State changed via going through gate \n
        '''
        assert wire_index1 < self.qn or wire_index2 < self.qn, (
            'Input argument should be between wire 0 to ' + str(self.qn - 1))

        if self.qn == 2:
            self.state = SparseMatrix.dot(QG.SWAP, self.state)
        else:
            if wire_index1 < wire_index2:
                a = wire_index1
            else:
                a = wire_index2
            gate_list = []
            for i in range(self.qn - 1):
                if i == a:
                    gate_list.append(QG.SWAP)
                else:
                    gate_list.append(QG.eye)
            gate_M = gate_list[0]
            for i in range(1, self.qn - 1):
                gate_M = SparseMatrix.tensordot(gate_M, gate_list[i])
            self.state = SparseMatrix.dot(gate_M, self.state)
    def apply_pauliZ(self, wire_index):
        '''
        Method applying the Pauli Z gate to the quantum state \n
        @param wire_index: Integer indicating location of gate \n
        @return: State changed via going through gate \n
        '''
        assert -1 < wire_index < self.qn, (
            'Input argument should be between wire 0 to ' + str(self.qn - 1))

        if self.qn == 1:
            self.state = SparseMatrix.dot(QG.PZ, self.state)
        else:
            gate_list = []
            for i in range(self.qn):
                if i == wire_index:
                    gate_list.append(QG.PZ)
                else:
                    gate_list.append(QG.eye)
            gate_M = gate_list[0]
            for i in range(1, self.qn):
                gate_M = SparseMatrix.tensordot(gate_M, gate_list[i])
            self.state = SparseMatrix.dot(gate_M, self.state)
    def apply_amplification(self):
        '''
        Method applying amplitude amplification of marked item \n
        @return: Changed qubit state via amplification of marked item \n
        '''
        s = np.zeros(2**self.qn)
        s[0] = 1
        s = SparseMatrix.sparsify(s.reshape(len(s), 1))
        gate_list = []
        for i in range(self.qn):
            gate_list.append(QG.H)

        H = gate_list[0]
        for i in range(1, self.qn):
            H = SparseMatrix.tensordot(H, gate_list[i])
        s = SparseMatrix.dot(H, s)
        s_T = SparseMatrix.transpose(s)
        s_s = SparseMatrix.tensordot(s, s_T)
        s_s_2 = SparseMatrix.multiply(s_s, 2)
        eye = SparseMatrix.sparsify(np.eye(2**self.qn))
        diffuser = SparseMatrix.minus(s_s_2, eye)
        self.state = SparseMatrix.dot(diffuser, self.state)
 def apply_grover_oracle(self, marks):
     '''
     Method to apply grover oracle \n
     @param marks: Integer or list of location for oracle \n
     @return: Changed qubit state with grover oracle \n
     '''
     eye = np.eye(2**self.qn)
     oracle = eye
     if isinstance(marks, int):
         oracle[marks][marks] = -1
     else:
         for mark in marks:
             oracle[mark][mark] = -1
     oracle = SparseMatrix.sparsify(oracle)
     self.state = SparseMatrix.dot(oracle, self.state)