|
14 | 14 | r""" |
15 | 15 | Contains the Superposition template. |
16 | 16 | """ |
17 | | - |
18 | 17 | import pennylane as qml |
19 | 18 | from pennylane.operation import Operation |
20 | 19 |
|
21 | 20 |
|
22 | | -def _assign_states(basis_list): |
| 21 | +def order_states(basis_states: list[list[int]]) -> dict[tuple[int], tuple[int]]: |
23 | 22 | r""" |
24 | | - This function maps a given list of :math:`m` basis states to the first :math:`m` basis states in the |
25 | | - computational basis. |
26 | | -
|
27 | | - For instance, a given list of :math:`[s_0, s_1, ..., s_m]` where :math:`s` is a basis |
28 | | - state of length :math:`4` will be mapped as :math:`{s_0: |0000\rangle, s_1: |0001\rangle, s_2: |0010\rangle, \dots}`. |
29 | | -
|
30 | | - Note that if a state in ``basis_list`` is one of the first :math:`m` basis states, |
31 | | - this state will be mapped to itself. |
| 23 | + This function maps a given list of :math:`m` computational basis states to the first |
| 24 | + :math:`m` computational basis states, except for input states that are among the first |
| 25 | + :math:`m` computational basis states, which are mapped to themselves. |
32 | 26 |
|
33 | 27 | Args: |
34 | | - basis_list (list): list of basis states to be mapped |
| 28 | + basis_states (list[list[int]]): sequence of :math:`m` basis states to be mapped. |
| 29 | + Each state is a sequence of 0s and 1s. |
35 | 30 |
|
36 | 31 | Returns: |
37 | | - dict: dictionary mapping basis states to the first :math:`m` basis states |
| 32 | + dict[tuple[int], tuple[int]]: dictionary mapping basis states to the first :math:`m` basis |
| 33 | + states, except for fixed points (states in the input that already were among the |
| 34 | + first :math:`m` basis states). |
38 | 35 |
|
| 36 | + **Example** |
39 | 37 |
|
40 | | - ** Example ** |
| 38 | + For instance, a given list of :math:`[s_0, s_1, ..., s_m]` where :math:`s` is a basis |
| 39 | + state of length :math:`4` will be mapped as |
| 40 | + :math:`\{s_0: |0000\rangle, s_1: |0001\rangle, s_2: |0010\rangle, \dots\}`. |
41 | 41 |
|
42 | 42 | .. code-block:: pycon |
43 | 43 |
|
44 | | - >>> basis_list = [[1, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 0, 1]] |
45 | | - >>> _assign_states(basis_list) |
46 | | - { |
47 | | - [1, 1, 0, 0]: [0, 0, 0, 0], |
48 | | - [1, 0, 1, 0]: [0, 0, 0, 1], |
49 | | - [0, 1, 0, 1]: [0, 0, 1, 0], |
50 | | - [1, 0, 0, 1]: [0, 0, 1, 1] |
51 | | - } |
| 44 | + >>> basis_states = [[1, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 0, 1]] |
| 45 | + >>> order_states(basis_states) |
| 46 | + {(1, 1, 0, 0): (0, 0, 0, 0), |
| 47 | + (1, 0, 1, 0): (0, 0, 0, 1), |
| 48 | + (0, 1, 0, 1): (0, 0, 1, 0), |
| 49 | + (1, 0, 0, 1): (0, 0, 1, 1)} |
52 | 50 |
|
| 51 | + If a state in ``basis_states`` is one of the first :math:`m` basis states, |
| 52 | + this state will be mapped to itself, i.e. it will be a fixed point of the mapping. |
53 | 53 |
|
54 | 54 | .. code-block:: pycon |
55 | 55 |
|
56 | | - >>> basis_list = [[1, 1, 0, 0], [0, 1, 0, 1], [0, 0, 0, 1], [1, 0, 0, 1]] |
57 | | - >>> _assign_states(basis_list) |
58 | | - { |
59 | | - [1, 1, 0, 0]: [0, 0, 0, 0], |
60 | | - [0, 1, 0, 1]: [0, 0, 1, 0], |
61 | | - [0, 0, 0, 1]: [0, 0, 0, 1], |
62 | | - [1, 0, 0, 1]: [0, 0, 1, 1] |
63 | | - } |
| 56 | + >>> basis_states = [[1, 1, 0, 0], [0, 1, 0, 1], [0, 0, 0, 1], [1, 0, 0, 1]] |
| 57 | + >>> order_states(basis_states) |
| 58 | + {(0, 0, 0, 1): (0, 0, 0, 1), |
| 59 | + (1, 1, 0, 0): (0, 0, 0, 0), |
| 60 | + (0, 1, 0, 1): (0, 0, 1, 0), |
| 61 | + (1, 0, 0, 1): (0, 0, 1, 1)} |
64 | 62 |
|
65 | 63 | """ |
66 | 64 |
|
67 | | - length = len(basis_list[0]) |
68 | | - smallest_basis_lists = [tuple(map(int, f"{i:0{length}b}")) for i in range(len(basis_list))] |
69 | | - |
70 | | - binary_dict = {} |
71 | | - used_smallest = set() |
72 | | - |
73 | | - # Assign keys that can map to themselves |
74 | | - for original in basis_list: |
75 | | - |
76 | | - if original in smallest_basis_lists and tuple(original) not in used_smallest: |
77 | | - |
78 | | - binary_dict[tuple(original)] = original |
79 | | - used_smallest.add(tuple(original)) |
| 65 | + m = len(basis_states) |
| 66 | + length = len(basis_states[0]) |
| 67 | + # Create the integers corresponding to the input basis states |
| 68 | + basis_ints = [int("".join(map(str, state)), 2) for state in basis_states] |
80 | 69 |
|
81 | | - # Assign remaining keys to unused binary lists |
82 | | - remaining_keys = [key for key in basis_list if tuple(key) not in binary_dict] |
83 | | - remaining_values = [ |
84 | | - value for value in smallest_basis_lists if tuple(value) not in used_smallest |
85 | | - ] |
| 70 | + basis_states = [tuple(s) for s in basis_states] # Need hashable objects, so we use tuples |
| 71 | + state_map = {} # The map for basis states to be populated |
| 72 | + unmapped_states = [] # Will collect non-fixed point states |
| 73 | + unmapped_ints = {i: None for i in range(m)} # Will remove fixed point states |
| 74 | + # Map fixed-point states to themselves and collect states and target ints still to be paired |
| 75 | + for b_int, state in zip(basis_ints, basis_states): |
| 76 | + if b_int < m: |
| 77 | + state_map[state] = state |
| 78 | + unmapped_ints.pop(b_int) |
| 79 | + else: |
| 80 | + unmapped_states.append(state) |
86 | 81 |
|
87 | | - for key, value in zip(remaining_keys, remaining_values): |
88 | | - binary_dict[tuple(key)] = value |
89 | | - used_smallest.add(tuple(value)) |
| 82 | + # Map non-fixed point states |
| 83 | + for state, new_b_int in zip(unmapped_states, unmapped_ints): |
| 84 | + # Convert the index of the state to be mapped into a state itself |
| 85 | + state_map[state] = tuple(map(int, f"{new_b_int:0{length}b}")) |
90 | 86 |
|
91 | | - return binary_dict |
| 87 | + return state_map |
92 | 88 |
|
93 | 89 |
|
94 | 90 | def _permutation_operator(basis1, basis2, wires, work_wire): |
@@ -292,7 +288,7 @@ def compute_decomposition(coeffs, bases, wires, work_wire): # pylint: disable=a |
292 | 288 | """ |
293 | 289 |
|
294 | 290 | dic_state = dict(zip(bases, coeffs)) |
295 | | - perms = _assign_states(bases) |
| 291 | + perms = order_states(bases) |
296 | 292 | new_dic_state = {perms[key]: dic_state[key] for key in dic_state if key in perms} |
297 | 293 |
|
298 | 294 | sorted_coefficients = [ |
|
0 commit comments