1 from itertools
import dropwhile
4 from squander.partitioning.tools
import build_dependency
9 Partition a circuit greedily using Kahn's algorithm 13 c: SQUANDER Circuit to partition 15 max_qubit: Max qubits per partition 17 preparts: Optional predefined partitions 21 Partitioned circuit, parameter order (source_idx, dest_idx, param_count), partition assignments 25 S = [(tuple(sorted(gate_to_qubit[x])), x)
for x
in S]
31 def partition_condition(idx):
32 return len(gate_to_qubit[S[idx][1]] | curr_partition) > max_qubit
34 def partition_condition(idx):
35 return not S[idx][1]
in preparts[len(parts)-1]
37 curr_partition = set()
43 idx = next(dropwhile(partition_condition, range(len(S))),
None)
44 n = S[idx][1]
if idx
is not None else None 45 if preparts
is not None:
46 assert (n
is None) == (len(preparts[len(parts)-1]) == len(parts[-1]))
50 total += len(parts[-1])
52 curr_partition = set()
54 idx = next(dropwhile(partition_condition, range(len(S))),
None)
55 n = S[idx][1]
if idx
is not None else None 60 curr_partition |= gate_to_qubit[n]
66 assert len(rg[n]) == 0
67 for child
in set(g[n]):
71 heapq.heappush(S, (tuple(sorted(gate_to_qubit[child])), child))
74 total += len(parts[-1])
75 assert total == len(gate_dict)
82 Build partitioned circuit from predefined partitions 86 c: SQUANDER Circuit to partition 88 max_qubit: Max qubits per partition 90 preparts: Predefined partition assignments 94 Partitioned circuit, parameter order (source_idx, dest_idx, param_count), partition assignments 96 top_circuit = Circuit(c.get_Qbit_Num())
100 S = [(tuple(sorted(gate_to_qubit[x])), x)
for x
in S]
109 def partition_condition(idx):
110 return len(gate_to_qubit[S[idx][1]] | curr_partition) > max_qubit
112 def partition_condition(idx):
113 return not S[idx][1]
in preparts[len(parts)-1]
115 c = Circuit(c.get_Qbit_Num())
116 curr_partition = set()
122 idx = next(dropwhile(partition_condition, range(len(S))),
None)
123 n = S[idx][1]
if idx
is not None else None 124 if preparts
is not None:
125 assert (n
is None) == (len(preparts[len(parts)-1]) == len(parts[-1]))
129 top_circuit.add_Circuit(c)
130 total += len(c.get_Gates())
132 curr_partition = set()
133 c = Circuit(c.get_Qbit_Num())
135 idx = next(dropwhile(partition_condition, range(len(S))),
None)
136 n = S[idx][1]
if idx
is not None else None 141 curr_partition |= gate_to_qubit[n]
142 c.add_Gate(gate_dict[n])
144 gate_dict[n].get_Parameter_Start_Index(),
153 assert len(rg[n]) == 0
154 for child
in set(g[n]):
158 heapq.heappush(S, (tuple(sorted(gate_to_qubit[child])), child))
161 top_circuit.add_Circuit(c)
162 total += len(c.get_Gates())
163 assert total == len(gate_dict)
165 return top_circuit, param_order, parts
170 Split partitions into connected components 174 preparts: Initial partitions 176 g: Forward dependency graph 178 rg: Reverse dependency graph 182 List of split partitions 185 for part
in preparts:
198 ord_dict = {x: i
for i, part
in enumerate(preparts)
for x
in part}
199 return [list(sorted(x, key=ord_dict.get))
for x
in L]
204 Test split_partition function for correctness. 215 expected = [[0, 1, 2], [3, 4]]
223 assert { frozenset(x)
for x
in expected } == { frozenset(x)
for x
in split }
226 if __name__ ==
"__main__":
def kahn_partition(c, max_qubit, preparts=None)
def kahn_partition_preparts(c, max_qubit, preparts)
def test_split_partition()
def split_partition(preparts, g, rg)
def get_Parameter_Num(self)
Call to get the number of free parameters in the gate structure used for the decomposition.