Skip to content

Commit 1948e73

Browse files
authored
Change signature of cirq_ft.And gate to use directional registers like Qualtran (#6302)
* Change signature of gate to use directional registers like Qualtran * Remove debug prints
1 parent c696323 commit 1948e73

9 files changed

+112
-88
lines changed

cirq-ft/cirq_ft/algos/and_gate.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,16 @@ def _validate_cv(self, attribute, value):
6161

6262
@cached_property
6363
def signature(self) -> infra.Signature:
64-
return infra.Signature.build(control=len(self.cv), ancilla=len(self.cv) - 2, target=1)
64+
one_side = infra.Side.RIGHT if not self.adjoint else infra.Side.LEFT
65+
n_cv = len(self.cv)
66+
junk_reg = [infra.Register('junk', 1, shape=n_cv - 2, side=one_side)] if n_cv > 2 else []
67+
return infra.Signature(
68+
[
69+
infra.Register('ctrl', 1, shape=n_cv),
70+
*junk_reg,
71+
infra.Register('target', 1, side=one_side),
72+
]
73+
)
6574

6675
def __pow__(self, power: int) -> "And":
6776
if power == 1:
@@ -142,9 +151,9 @@ def decompose_from_registers(
142151
self, *, context: cirq.DecompositionContext, **quregs: NDArray[cirq.Qid]
143152
) -> cirq.OP_TREE:
144153
control, ancilla, target = (
145-
quregs['control'],
146-
quregs.get('ancilla', np.array([])),
147-
quregs['target'],
154+
quregs['ctrl'].flatten(),
155+
quregs.get('junk', np.array([])).flatten(),
156+
quregs['target'].flatten(),
148157
)
149158
if len(self.cv) == 2:
150159
yield self._decompose_single_and(

cirq-ft/cirq_ft/algos/and_gate_test.py

+74-71
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def random_cv(n: int) -> List[int]:
4646
def test_multi_controlled_and_gate(cv: List[int]):
4747
gate = cirq_ft.And(cv)
4848
r = gate.signature
49-
assert r.get_left('ancilla').total_bits() == r.get_left('control').total_bits() - 2
49+
assert r.get_right('junk').total_bits() == r.get_left('ctrl').total_bits() - 2
5050
quregs = infra.get_named_qubits(r)
5151
and_op = gate.on_registers(**quregs)
5252
circuit = cirq.Circuit(and_op)
@@ -55,7 +55,7 @@ def test_multi_controlled_and_gate(cv: List[int]):
5555
qubit_order = infra.merge_qubits(gate.signature, **quregs)
5656

5757
for input_control in input_controls:
58-
initial_state = input_control + [0] * (r.get_left('ancilla').total_bits() + 1)
58+
initial_state = input_control + [0] * (r.get_right('junk').total_bits() + 1)
5959
result = cirq.Simulator(dtype=np.complex128).simulate(
6060
circuit, initial_state=initial_state, qubit_order=qubit_order
6161
)
@@ -80,64 +80,67 @@ def test_and_gate_diagram():
8080
gate = cirq_ft.And((1, 0, 1, 0, 1, 0))
8181
qubit_regs = infra.get_named_qubits(gate.signature)
8282
op = gate.on_registers(**qubit_regs)
83-
# Qubit order should be alternating (control, ancilla) pairs.
84-
c_and_a = sum(zip(qubit_regs["control"][1:], qubit_regs["ancilla"]), ()) + (
85-
qubit_regs["control"][-1],
83+
ctrl, junk, target = (
84+
qubit_regs["ctrl"].flatten(),
85+
qubit_regs["junk"].flatten(),
86+
qubit_regs['target'].flatten(),
8687
)
87-
qubit_order = np.concatenate([qubit_regs["control"][0:1], c_and_a, qubit_regs["target"]])
88+
# Qubit order should be alternating (control, ancilla) pairs.
89+
c_and_a = sum(zip(ctrl[1:], junk), ()) + (ctrl[-1],)
90+
qubit_order = np.concatenate([ctrl[0:1], c_and_a, target])
8891
# Test diagrams.
8992
cirq.testing.assert_has_diagram(
9093
cirq.Circuit(op),
9194
"""
92-
control0: ───@─────
93-
94-
control1: ───(0)───
95-
96-
ancilla0: ───Anc───
97-
98-
control2: ───@─────
99-
100-
ancilla1: ───Anc───
101-
102-
control3: ───(0)───
103-
104-
ancilla2: ───Anc───
105-
106-
control4: ───@─────
107-
108-
ancilla3: ───Anc───
109-
110-
control5: ───(0)───
111-
112-
target: ────And───
95+
ctrl[0]: ───@─────
96+
97+
ctrl[1]: ───(0)───
98+
99+
junk[0]: ───Anc───
100+
101+
ctrl[2]: ───@─────
102+
103+
junk[1]: ───Anc───
104+
105+
ctrl[3]: ───(0)───
106+
107+
junk[2]: ───Anc───
108+
109+
ctrl[4]: ───@─────
110+
111+
junk[3]: ───Anc───
112+
113+
ctrl[5]: ───(0)───
114+
115+
target: ────And───
113116
""",
114117
qubit_order=qubit_order,
115118
)
116119
cirq.testing.assert_has_diagram(
117120
cirq.Circuit(op**-1),
118121
"""
119-
control0: ───@──────
120-
121-
control1: ───(0)────
122-
123-
ancilla0: ───Anc────
124-
125-
control2: ───@──────
126-
127-
ancilla1: ───Anc────
128-
129-
control3: ───(0)────
130-
131-
ancilla2: ───Anc────
132-
133-
control4: ───@──────
134-
135-
ancilla3: ───Anc────
136-
137-
control5: ───(0)────
138-
139-
target: ────And†───
140-
""",
122+
ctrl[0]: ───@──────
123+
124+
ctrl[1]: ───(0)────
125+
126+
junk[0]: ───Anc────
127+
128+
ctrl[2]: ───@──────
129+
130+
junk[1]: ───Anc────
131+
132+
ctrl[3]: ───(0)────
133+
134+
junk[2]: ───Anc────
135+
136+
ctrl[4]: ───@──────
137+
138+
junk[3]: ───Anc────
139+
140+
ctrl[5]: ───(0)────
141+
142+
target: ────And†───
143+
""",
141144
qubit_order=qubit_order,
142145
)
143146
# Test diagram of decomposed 3-qubit and ladder.
@@ -147,28 +150,28 @@ def test_and_gate_diagram():
147150
cirq.testing.assert_has_diagram(
148151
decomposed_circuit,
149152
"""
150-
control0: ───@─────────────────────────────────────────────────────────@──────
151-
│ │
152-
control1: ───(0)───────────────────────────────────────────────────────(0)────
153-
│ │
154-
ancilla0: ───And───@────────────────────────────────────────────@──────And†───
155-
│ │
156-
control2: ─────────@────────────────────────────────────────────@─────────────
157-
│ │
158-
ancilla1: ─────────And───@───────────────────────────────@──────And†──────────
159-
│ │
160-
control3: ───────────────(0)─────────────────────────────(0)──────────────────
161-
│ │
162-
ancilla2: ───────────────And───@──────────────────@──────And†─────────────────
163-
│ │
164-
control4: ─────────────────────@──────────────────@───────────────────────────
165-
│ │
166-
ancilla3: ─────────────────────And───@─────@──────And†────────────────────────
167-
│ │
168-
control5: ───────────────────────────(0)───(0)────────────────────────────────
169-
│ │
170-
target: ────────────────────────────And───And†───────────────────────────────
171-
""",
153+
ctrl[0]: ───@─────────────────────────────────────────────────────────@──────
154+
│ │
155+
ctrl[1]: ───(0)───────────────────────────────────────────────────────(0)────
156+
│ │
157+
junk[0]: ───And───@────────────────────────────────────────────@──────And†───
158+
│ │
159+
ctrl[2]: ─────────@────────────────────────────────────────────@─────────────
160+
│ │
161+
junk[1]: ─────────And───@───────────────────────────────@──────And†──────────
162+
│ │
163+
ctrl[3]: ───────────────(0)─────────────────────────────(0)──────────────────
164+
│ │
165+
junk[2]: ───────────────And───@──────────────────@──────And†─────────────────
166+
│ │
167+
ctrl[4]: ─────────────────────@──────────────────@───────────────────────────
168+
│ │
169+
junk[3]: ─────────────────────And───@─────@──────And†────────────────────────
170+
│ │
171+
ctrl[5]: ───────────────────────────(0)───(0)────────────────────────────────
172+
│ │
173+
target: ────────────────────────────And───And†───────────────────────────────
174+
""",
172175
qubit_order=qubit_order,
173176
)
174177

cirq-ft/cirq_ft/algos/hubbard_model.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,13 @@ def decompose_from_registers(
335335
and_target = context.qubit_manager.qalloc(1)
336336
and_anc = context.qubit_manager.qalloc(1)
337337
yield and_gate.And(cv=(0, 0, 1)).on_registers(
338-
control=[*U, *V, temp[-1]], ancilla=and_anc, target=and_target
338+
ctrl=np.array([U, V, temp[-1:]]), junk=np.array([and_anc]), target=and_target
339339
)
340340
yield swap_network.MultiTargetCSwap.make_on(
341341
control=and_target, target_x=[*p_x, *p_y, *alpha], target_y=[*q_x, *q_y, *beta]
342342
)
343343
yield and_gate.And(cv=(0, 0, 1), adjoint=True).on_registers(
344-
control=[*U, *V, temp[-1]], ancilla=and_anc, target=and_target
344+
ctrl=np.array([U, V, temp[-1:]]), junk=np.array([and_anc]), target=and_target
345345
)
346346
context.qubit_manager.qfree([*and_anc, *and_target])
347347

cirq-ft/cirq_ft/algos/multi_control_multi_target_pauli.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ def decompose_from_registers(
8585
) -> cirq.OP_TREE:
8686
controls, target = quregs['controls'], quregs['target']
8787
qm = context.qubit_manager
88-
and_ancilla, and_target = qm.qalloc(len(self.cvs) - 2), qm.qalloc(1)
88+
and_ancilla, and_target = np.array(qm.qalloc(len(self.cvs) - 2)), qm.qalloc(1)
8989
yield and_gate.And(self.cvs).on_registers(
90-
control=controls, ancilla=and_ancilla, target=and_target
90+
ctrl=controls[:, np.newaxis], junk=and_ancilla[:, np.newaxis], target=and_target
9191
)
9292
yield self.target_gate.on(*target).controlled_by(*and_target)
9393
yield and_gate.And(self.cvs, adjoint=True).on_registers(
94-
control=controls, ancilla=and_ancilla, target=and_target
94+
ctrl=controls[:, np.newaxis], junk=and_ancilla[:, np.newaxis], target=and_target
9595
)
96-
qm.qfree(and_ancilla + and_target)
96+
qm.qfree([*and_ancilla, *and_target])
9797

9898
def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo:
9999
wire_symbols = ["@" if b else "@(0)" for b in self.cvs]

cirq-ft/cirq_ft/algos/prepare_uniform_superposition.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ def decompose_from_registers(
9494

9595
and_ancilla = context.qubit_manager.qalloc(len(self.cv) + logL - 2)
9696
and_op = and_gate.And((0,) * logL + self.cv).on_registers(
97-
control=[*logL_qubits, *controls], ancilla=and_ancilla, target=ancilla
97+
ctrl=np.asarray([*logL_qubits, *controls])[:, np.newaxis],
98+
junk=np.asarray(and_ancilla)[:, np.newaxis],
99+
target=ancilla,
98100
)
99101
yield and_op
100102
yield cirq.Rz(rads=theta)(*ancilla)

cirq-ft/cirq_ft/algos/qrom.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ def decompose_zero_selection(
150150
and_ancilla = context.qubit_manager.qalloc(len(controls) - 2)
151151
and_target = context.qubit_manager.qalloc(1)[0]
152152
multi_controlled_and = and_gate.And((1,) * len(controls)).on_registers(
153-
control=controls, ancilla=and_ancilla, target=and_target
153+
ctrl=np.array(controls)[:, np.newaxis],
154+
junk=np.array(and_ancilla)[:, np.newaxis],
155+
target=and_target,
154156
)
155157
yield multi_controlled_and
156158
yield self._load_nth_data(zero_indx, lambda q: cirq.CNOT(and_target, q), **target_regs)

cirq-ft/cirq_ft/algos/unary_iteration_gate.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ def _unary_iteration_multi_controls(
153153
and_ancilla = ancilla[: num_controls - 2]
154154
and_target = ancilla[num_controls - 2]
155155
multi_controlled_and = and_gate.And((1,) * len(controls)).on_registers(
156-
control=np.array(controls), ancilla=np.array(and_ancilla), target=and_target
156+
ctrl=np.array(controls).reshape(len(controls), 1),
157+
junk=np.array(and_ancilla).reshape(len(and_ancilla), 1),
158+
target=and_target,
157159
)
158160
ops.append(multi_controlled_and)
159161
yield from _unary_iteration_single_control(

cirq-ft/cirq_ft/infra/jupyter_tools_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_svg_circuit():
2727
svg_str = svg.data
2828

2929
# check that the order is respected in the svg data.
30-
assert svg_str.find('control') < svg_str.find('ancilla') < svg_str.find('target')
30+
assert svg_str.find('ctrl') < svg_str.find('junk') < svg_str.find('target')
3131

3232
# Check svg_circuit raises.
3333
with pytest.raises(ValueError):

cirq-ft/cirq_ft/infra/testing_test.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@ def test_assert_circuit_inp_out_cirqsim():
3434
def test_gate_helper():
3535
g = cirq_ft.testing.GateHelper(cirq_ft.And(cv=(1, 0, 1, 0)))
3636
assert g.gate == cirq_ft.And(cv=(1, 0, 1, 0))
37-
assert g.r == cirq_ft.Signature.build(control=4, ancilla=2, target=1)
37+
assert g.r == cirq_ft.Signature(
38+
[
39+
cirq_ft.Register('ctrl', bitsize=1, shape=4),
40+
cirq_ft.Register('junk', bitsize=1, shape=2, side=cirq_ft.infra.Side.RIGHT),
41+
cirq_ft.Register('target', bitsize=1, side=cirq_ft.infra.Side.RIGHT),
42+
]
43+
)
3844
expected_quregs = {
39-
'control': cirq.NamedQubit.range(4, prefix='control'),
40-
'ancilla': cirq.NamedQubit.range(2, prefix='ancilla'),
45+
'ctrl': np.array([[cirq.q(f'ctrl[{i}]')] for i in range(4)]),
46+
'junk': np.array([[cirq.q(f'junk[{i}]')] for i in range(2)]),
4147
'target': [cirq.NamedQubit('target')],
4248
}
4349
for key in expected_quregs:

0 commit comments

Comments
 (0)