@@ -28,12 +28,12 @@ def _unary_iteration_segtree(
2828 ops : List [cirq .Operation ],
2929 control : cirq .Qid ,
3030 selection : Sequence [cirq .Qid ],
31+ ancilla : Sequence [cirq .Qid ],
3132 sl : int ,
3233 l : int ,
3334 r : int ,
3435 l_iter : int ,
3536 r_iter : int ,
36- qm : cirq .QubitManager ,
3737) -> Iterator [Tuple [cirq .OP_TREE , cirq .Qid , int ]]:
3838 """Constructs a unary iteration circuit by iterating over nodes of an implicit Segment Tree.
3939
@@ -45,6 +45,8 @@ def _unary_iteration_segtree(
4545 selection: Sequence of selection qubits. The i'th qubit in the list corresponds to the i'th
4646 level in the segment tree.Thus, a total of O(logN) selection qubits are required for a
4747 tree on range `N = (r_iter - l_iter)`.
48+ ancilla: Pre-allocated ancilla qubits to be used for constructing the unary iteration
49+ circuit.
4850 sl: Current depth of the tree. `selection[sl]` gives the selection qubit corresponding to
4951 the current depth.
5052 l: Left index of the range represented by current node of the segment tree.
@@ -76,73 +78,73 @@ def _unary_iteration_segtree(
7678 if r_iter <= m :
7779 # Yield only left sub-tree.
7880 yield from _unary_iteration_segtree (
79- ops , control , selection , sl + 1 , l , m , l_iter , r_iter , qm
81+ ops , control , selection , ancilla , sl + 1 , l , m , l_iter , r_iter
8082 )
8183 return
8284 if l_iter >= m :
8385 # Yield only right sub-tree
8486 yield from _unary_iteration_segtree (
85- ops , control , selection , sl + 1 , m , r , l_iter , r_iter , qm
87+ ops , control , selection , ancilla , sl + 1 , m , r , l_iter , r_iter
8688 )
8789 return
88- anc , sq = qm . qalloc ( 1 )[ 0 ], selection [sl ]
90+ anc , sq = ancilla [ sl ], selection [sl ]
8991 ops .append (and_gate .And ((1 , 0 )).on (control , sq , anc ))
90- yield from _unary_iteration_segtree (ops , anc , selection , sl + 1 , l , m , l_iter , r_iter , qm )
92+ yield from _unary_iteration_segtree (ops , anc , selection , ancilla , sl + 1 , l , m , l_iter , r_iter )
9193 ops .append (cirq .CNOT (control , anc ))
92- yield from _unary_iteration_segtree (ops , anc , selection , sl + 1 , m , r , l_iter , r_iter , qm )
94+ yield from _unary_iteration_segtree (ops , anc , selection , ancilla , sl + 1 , m , r , l_iter , r_iter )
9395 ops .append (and_gate .And (adjoint = True ).on (control , sq , anc ))
94- qm .qfree ([anc ])
9596
9697
9798def _unary_iteration_zero_control (
9899 ops : List [cirq .Operation ],
99100 selection : Sequence [cirq .Qid ],
101+ ancilla : Sequence [cirq .Qid ],
100102 l_iter : int ,
101103 r_iter : int ,
102- qm : cirq .QubitManager ,
103104) -> Iterator [Tuple [cirq .OP_TREE , cirq .Qid , int ]]:
104105 sl , l , r = 0 , 0 , 2 ** len (selection )
105106 m = (l + r ) >> 1
106107 ops .append (cirq .X (selection [0 ]))
107108 yield from _unary_iteration_segtree (
108- ops , selection [0 ], selection [1 :], sl , l , m , l_iter , r_iter , qm
109+ ops , selection [0 ], selection [1 :], ancilla , sl , l , m , l_iter , r_iter
109110 )
110111 ops .append (cirq .X (selection [0 ]))
111112 yield from _unary_iteration_segtree (
112- ops , selection [0 ], selection [1 :], sl , m , r , l_iter , r_iter , qm
113+ ops , selection [0 ], selection [1 :], ancilla , sl , m , r , l_iter , r_iter
113114 )
114115
115116
116117def _unary_iteration_single_control (
117118 ops : List [cirq .Operation ],
118119 control : cirq .Qid ,
119120 selection : Sequence [cirq .Qid ],
121+ ancilla : Sequence [cirq .Qid ],
120122 l_iter : int ,
121123 r_iter : int ,
122- qm : cirq .QubitManager ,
123124) -> Iterator [Tuple [cirq .OP_TREE , cirq .Qid , int ]]:
124125 sl , l , r = 0 , 0 , 2 ** len (selection )
125- yield from _unary_iteration_segtree (ops , control , selection , sl , l , r , l_iter , r_iter , qm )
126+ yield from _unary_iteration_segtree (ops , control , selection , ancilla , sl , l , r , l_iter , r_iter )
126127
127128
128129def _unary_iteration_multi_controls (
129130 ops : List [cirq .Operation ],
130131 controls : Sequence [cirq .Qid ],
131132 selection : Sequence [cirq .Qid ],
133+ ancilla : Sequence [cirq .Qid ],
132134 l_iter : int ,
133135 r_iter : int ,
134- qm : cirq .QubitManager ,
135136) -> Iterator [Tuple [cirq .OP_TREE , cirq .Qid , int ]]:
136137 num_controls = len (controls )
137- and_ancilla = qm . qalloc ( num_controls - 2 )
138- and_target = qm . qalloc ( 1 )[ 0 ]
138+ and_ancilla = ancilla [: num_controls - 2 ]
139+ and_target = ancilla [ num_controls - 2 ]
139140 multi_controlled_and = and_gate .And ((1 ,) * len (controls )).on_registers (
140141 control = np .array (controls ), ancilla = np .array (and_ancilla ), target = and_target
141142 )
142143 ops .append (multi_controlled_and )
143- yield from _unary_iteration_single_control (ops , and_target , selection , l_iter , r_iter , qm )
144+ yield from _unary_iteration_single_control (
145+ ops , and_target , selection , ancilla [num_controls - 1 :], l_iter , r_iter
146+ )
144147 ops .append (cirq .inverse (multi_controlled_and ))
145- qm .qfree (and_ancilla + [and_target ])
146148
147149
148150def unary_iteration (
@@ -203,18 +205,18 @@ def unary_iteration(
203205 """
204206 assert 2 ** len (selection ) >= r_iter - l_iter
205207 assert len (selection ) > 0
208+ ancilla = qubit_manager .qalloc (max (0 , len (controls ) + len (selection ) - 1 ))
206209 if len (controls ) == 0 :
207- yield from _unary_iteration_zero_control (
208- flanking_ops , selection , l_iter , r_iter , qubit_manager
209- )
210+ yield from _unary_iteration_zero_control (flanking_ops , selection , ancilla , l_iter , r_iter )
210211 elif len (controls ) == 1 :
211212 yield from _unary_iteration_single_control (
212- flanking_ops , controls [0 ], selection , l_iter , r_iter , qubit_manager
213+ flanking_ops , controls [0 ], selection , ancilla , l_iter , r_iter
213214 )
214215 else :
215216 yield from _unary_iteration_multi_controls (
216- flanking_ops , controls , selection , l_iter , r_iter , qubit_manager
217+ flanking_ops , controls , selection , ancilla , l_iter , r_iter
217218 )
219+ qubit_manager .qfree (ancilla )
218220
219221
220222class UnaryIterationGate (infra .GateWithRegisters ):
0 commit comments