def _compute_unitary_oracle_matrix( bitstring_map: Dict[str, str]) -> Tuple[np.ndarray, Dict[str, str]]: """ Computes the unitary matrix that encodes the orcale function for Simon's algorithm :param bitstring_map: A truth-table of the input bitstring map in dictionary format. :return: A dense matrix containing the permutation of the bit strings and a dictionary containing the indices of the non-zero elements of the computed permutation matrix as key-value-pairs. """ n_bits = len(list(bitstring_map.keys())[0]) # We instantiate an empty matrix of size 2 * n_bits to encode the mapping from n qubits # to n ancillae, which explains the factor 2 overhead. # To construct the matrix we go through all possible state transitions and pad the index # according to all possible states the ancilla-subsystem could be in ufunc = np.zeros(shape=(2**(2 * n_bits), 2**(2 * n_bits))) index_mapping_dct = defaultdict(dict) for b in range(2**n_bits): # padding according to ancilla state pad_str = np.binary_repr(b, n_bits) for k, v in bitstring_map.items(): # add mapping from initial state to the state in the ancilla system. # pad_str corresponds to the initial state of the ancilla system. index_mapping_dct[pad_str + k] = utils.bitwise_xor(pad_str, v) + k # calculate matrix indices that correspond to the transition-matrix-element # of the oracle unitary i, j = int(pad_str + k, 2), int(utils.bitwise_xor(pad_str, v) + k, 2) ufunc[i, j] = 1 return ufunc, index_mapping_dct
def create_1to1_bitmap(mask: str) -> Dict[str, str]: """ Create a bit map function (as a dictionary) for a given mask. e.g., for a mask :math:`m = 10` the return is a dictionary: >>> create_1to1_bitmap('10') ... { ... '00': '10', ... '01': '11', ... '10': '00', ... '11': '01' ... } :param mask: A binary mask as a string of 0's and 1's. :return: A dictionary containing a mapping of all possible bit strings of the same length as the mask's string and their mapped bit-string value. """ n_bits = len(mask) form_string = "{0:0" + str(n_bits) + "b}" bit_map_dct = {} for idx in range(2**n_bits): bit_string = form_string.format(idx) bit_map_dct[bit_string] = utils.bitwise_xor(bit_string, mask) return bit_map_dct
def _check_mask_correct(self): """ Checks if a given mask correctly reproduces the function that was provided to the Simon algorithm. This can be done in :math:`O(n)` as it is a simple list traversal. :return: True if mask reproduces the input function :rtype: Bool """ mask_str = ''.join([str(b) for b in self.mask]) return all([self.bit_map[k] == self.bit_map[utils.bitwise_xor(k, mask_str)] for k in self.bit_map.keys()])
def test_bit_masking(): bit_string = '101' mask_string = '110' assert u.bitwise_xor(bit_string, mask_string) == '011'