-
Notifications
You must be signed in to change notification settings - Fork 60
WIP: crosstalk-free GST #641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 141 commits
16e9309
c483ebb
56242ee
d249c80
dc964ad
8018e69
1d29ddb
19fcf3c
35e35fa
3e3210f
1253ee5
99392bf
6b6b69e
c54c4d0
a875d44
eef4b44
689ffa7
1d66e1c
028e961
9d2890a
5644b20
e96df9f
021fbf3
1821244
35d0353
5a90e5c
4f3ba4d
5f96a16
dd86821
7f0d9dd
a9b01a0
6c6fb53
284bbf9
2abdfa6
a018714
646c5d1
f2035ba
ced6d46
e7bb3c7
2f143f0
70843b4
3581769
12723be
56b8004
6003f75
1ca3b2d
6f43b2a
613379a
5de4bff
abb94ad
81e805a
23c6a3a
2ea2a6d
eb2ce64
27167a3
7d9f9b2
17294bc
06dbc64
7ad7b6d
f158ebf
3115499
6cad8d3
24930fb
e8be458
e991f6c
2616ae3
1f4d05b
3f82746
0f560f7
248fa7e
c9b1adf
75bb798
6ff9e05
5ff9873
fc80874
51474fd
338f8cf
9f8faad
4b9b10a
40d6460
cbb090f
650fd59
2025949
58c9c2b
8cf274c
e9f4576
1dcc580
2180de6
b037fab
8cec2d2
45c0317
60d23ed
eb85393
1d31a65
61ab0a1
e18e7dd
fe062e7
53b4eaa
c2a2393
68937ef
806a78f
0cc9464
421b690
ea49417
4cc5ba2
91d2d96
6e6dde0
7d639bb
3a413ca
773184e
c8c3bd0
f4b989c
e438351
0fcf1d8
eb9d122
80ecba9
ea18d5b
96c97f2
fa859ac
d73e251
a233602
ec00225
656bff3
661aa37
2fa4ad5
25af0e7
282cb59
74b6433
821e532
9bb7a59
84b5356
7992a6b
8226079
5a29f4b
d4e5db6
b3a226c
72303c3
19d43d5
525373e
bb78983
d0152d1
58d97e0
30ee59f
dd402cf
3431730
b4f7044
413ac67
3bd478e
8f57778
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tensor circuit construction should retain knowledge of original lane structure. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -201,6 +201,14 @@ def __setstate__(self, state_dict): | |
| self.__dict__.update(state_dict) | ||
| if 'uuid' not in state_dict: # backward compatibility | ||
| self.uuid = _uuid.uuid4() # create a new uuid | ||
|
|
||
| def tensor_circuits(self, other_circuitlist, new_name=None): | ||
| assert len(self) == len(other_circuitlist) | ||
| circuits = [] | ||
| for c1,c2 in zip(self._circuits, other_circuitlist._circuits): | ||
| circuits.append(c1.tensor_circuit(c2)) | ||
| out = CircuitList(circuits, name=new_name) | ||
| return out | ||
|
Comment on lines
+204
to
+211
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe worth merging. |
||
|
|
||
| def elementvec_to_array(self, elementvec, layout, mergeop="sum"): | ||
| """ | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: determine if we want to keep these new functions. Can see these functions in action in |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| import numpy as _np | ||
|
|
||
| from typing import Sequence, Dict, Tuple, Optional, Set | ||
| from pygsti.circuits import Circuit as Circuit | ||
| from pygsti.baseobjs.label import Label, LabelTupTup | ||
|
|
||
|
|
||
| def compute_qubit_to_lane_and_lane_to_qubits_mappings_for_circuit(circuit: Circuit) -> tuple[dict[int, int], | ||
| dict[int, tuple[int]]]: | ||
| """ | ||
| Parameters: | ||
| ------------ | ||
| circuit: Circuit - the circuit to compute qubit to lanes mapping for | ||
|
|
||
| num_qubits: int - The total number of qubits expected in the circuit. | ||
|
|
||
| Returns | ||
| -------- | ||
| Dictionary mapping qubit number to lane number in the circuit. | ||
| """ | ||
|
|
||
| qubits_to_potentially_entangled_others = {i: set((i,)) for i in range(circuit.num_lines)} | ||
| num_layers = circuit.num_layers | ||
| for layer_ind in range(num_layers): | ||
| layer = circuit.layer(layer_ind) | ||
| for op in layer: | ||
| qubits_used = op.qubits | ||
| for qb in qubits_used: | ||
| qubits_to_potentially_entangled_others[qb].update(set(qubits_used)) | ||
|
|
||
| lanes = {} | ||
| lan_num = 0 | ||
| visited: dict[int, int] = {} | ||
| def reachable_nodes(starting_point: int, | ||
| graph_qubits_to_neighbors: dict[int, set[int]], | ||
| visited: dict[int, set[int]]): | ||
| """ | ||
| Find which nodes are reachable from this starting point. | ||
| """ | ||
| if starting_point in visited: | ||
| return visited[starting_point] | ||
| else: | ||
| assert starting_point in graph_qubits_to_neighbors | ||
| visited[starting_point] = graph_qubits_to_neighbors[starting_point] | ||
| output = set(visited[starting_point]) | ||
| for child in graph_qubits_to_neighbors[starting_point]: | ||
| if child != starting_point: | ||
| output.update(output, reachable_nodes(child, graph_qubits_to_neighbors, visited)) | ||
| visited[starting_point] = output | ||
| return output | ||
|
|
||
| available_starting_points = list(sorted(qubits_to_potentially_entangled_others.keys())) | ||
| while available_starting_points: | ||
| sp = available_starting_points[0] | ||
| nodes = reachable_nodes(sp, qubits_to_potentially_entangled_others, visited) | ||
| for node in nodes: | ||
| available_starting_points.remove(node) | ||
| lanes[lan_num] = nodes | ||
| lan_num += 1 | ||
|
|
||
| def compute_qubits_to_lanes(lanes_to_qubits: dict[int, set[int]]) -> dict[int, int]: | ||
| """ | ||
| Determine a mapping from qubit to the lane it is in for this specific circuit. | ||
| """ | ||
| out = {} | ||
| for key, val in lanes_to_qubits.items(): | ||
| for qb in val: | ||
| out[qb] = key | ||
| return out | ||
|
|
||
| return compute_qubits_to_lanes(lanes), lanes | ||
|
|
||
|
|
||
| def compute_subcircuits(circuit: Circuit, | ||
| qubit_to_lanes: dict[int, int], | ||
| lane_to_qubits: dict[int, tuple[int, ...]], | ||
| cache_lanes_in_circuit: bool = False) -> list[list[LabelTupTup]]: | ||
| """ | ||
| Split a circuit into multiple subcircuits which do not talk across lanes. | ||
| """ | ||
|
|
||
| if "lanes" in circuit.saved_auxinfo: | ||
| # Check if the lane info matches and I can just return that set up. | ||
| if len(lane_to_qubits) == len(circuit.saved_auxinfo["lanes"]): | ||
| # We may have this already in cache. | ||
|
|
||
| lanes_to_gates = [[] for _ in range(len(lane_to_qubits))] | ||
| for i, key in lane_to_qubits.items(): | ||
| if tuple(sorted(key)) in circuit.saved_auxinfo["lanes"]: | ||
| lanes_to_gates[i] = circuit.saved_auxinfo["lanes"][tuple(sorted(key))] | ||
|
|
||
| else: | ||
| raise ValueError(f"lbl cache miss: {key} in circuit {circuit}") | ||
| return lanes_to_gates | ||
|
|
||
| lanes_to_gates = [[] for _ in range(_np.unique(list(qubit_to_lanes.values())).shape[0])] | ||
|
|
||
| num_layers = circuit.num_layers | ||
| for layer_ind in range(num_layers): | ||
| layer = circuit.layer_with_idles(layer_ind) | ||
| group = [] | ||
| group_lane = None | ||
| sorted_layer = sorted(layer, key=lambda x: x.qubits[0]) | ||
|
|
||
| for op in sorted_layer: | ||
| # We need this to be sorted by the qubit number so we do not get that a lane was split Q1 Q3 Q2 in the layer where Q1 and Q2 are in the same lane. | ||
| qubits_used = op.qubits # This will be a list of qubits used. | ||
| # I am assuming that the qubits are indexed numerically and not by strings. | ||
| lane = qubit_to_lanes[qubits_used[0]] | ||
|
|
||
| if group_lane is None: | ||
| group_lane = lane | ||
| group.append(op) | ||
| elif group_lane == lane: | ||
| group.append(op) | ||
| else: | ||
| lanes_to_gates[group_lane].append(LabelTupTup(tuple(group))) | ||
| group_lane = lane | ||
| group = [op] | ||
|
|
||
| if len(group) > 0: | ||
| # We have a left over group. | ||
| lanes_to_gates[group_lane].append(LabelTupTup(tuple(group))) | ||
|
|
||
| if cache_lanes_in_circuit: | ||
| circuit = circuit._cache_tensor_lanes(lanes_to_gates, lane_to_qubits) | ||
|
|
||
| if num_layers == 0: | ||
| return lanes_to_gates | ||
|
|
||
| return lanes_to_gates | ||
|
|
||
|
|
||
| @staticmethod | ||
| def batch_tensor( | ||
| circuits : Sequence[Circuit], | ||
| layer_mappers: Dict[int, Dict], | ||
| global_line_order: Optional[Tuple[int,...]] = None, | ||
| target_lines : Optional[Sequence[Tuple[int,...]]] = None | ||
| ) -> Circuit: | ||
| """ | ||
| """ | ||
| assert len(circuits) > 0 | ||
|
|
||
| if target_lines is None: | ||
| target_lines = [] | ||
| total_lines = 0 | ||
| max_cir_len = 0 | ||
| for c in circuits: | ||
| target_lines.append(tuple(range(total_lines, total_lines + c.num_lines))) | ||
| total_lines += c.num_lines | ||
| max_cir_len = max(max_cir_len, len(c)) | ||
| else: | ||
| total_lines = sum([c.num_lines for c in circuits]) | ||
| max_cir_len = max(*[len(c) for c in circuits]) | ||
|
|
||
| s : Set[int] = set() | ||
| for c, t in zip(circuits, target_lines): | ||
| assert not s.intersection(t) | ||
| assert len(t) == c.num_lines | ||
| s.update(t) | ||
|
|
||
| if global_line_order is None: | ||
| global_line_order = tuple(sorted(list(s))) | ||
|
|
||
| c = circuits[0].copy(editable=True) | ||
| c._append_idling_layers_inplace(max_cir_len - len(c)) | ||
| c.done_editing() | ||
| # ^ That changes the format of c._labels. We need to edit c while in this format, | ||
| # so the next line sets c._static = False. (We repeat this pattern in the loop below.) | ||
| c._static = False | ||
| c._labels = [layer_mappers[c.num_lines][ell] for ell in c._labels] | ||
| c.map_state_space_labels_inplace({k:v for k,v in zip(c.line_labels, target_lines[0])}) | ||
| c.done_editing() | ||
| for i, c2 in enumerate(circuits[1:]): | ||
| c2 = c2.copy(editable=True) | ||
| c2._append_idling_layers_inplace(max_cir_len - len(c2)) | ||
| c2.done_editing() | ||
| c2._static = False | ||
| c2._labels = [layer_mappers[c2.num_lines][ell] for ell in c2._labels] | ||
| c2.map_state_space_labels_inplace({k:v for k,v in zip(c2.line_labels, target_lines[i+1])}) | ||
| c2.done_editing() | ||
| c = c.tensor_circuit(c2) | ||
|
|
||
| c = c.reorder_lines(global_line_order) | ||
| return c |
Uh oh!
There was an error while loading. Please reload this page.