Skip to content

Commit 51ca852

Browse files
Remove uses of .device in cirq-pasqal in preparation for larger circuit.device deprecation (quantumlib#4757)
First devices removal as a part of quantumlib#4744 . The high level plan for deprecation is to: 1. pull all components of the library off of `.device` and onto `._device` to keep existing behavior working. 2. Deprecate dependent functionality that relies on `.device`. 3. After all dependency deprecations are done, deprecate the `.device` property in `cirq-core` circuits.py. 4. After the deprecation cycle is over, delete .device and _device properties from circuit, abstractcircuit, frozencircuit etc. This PR is tackles `cirq-pasqal`.
1 parent 6ba36bf commit 51ca852

File tree

5 files changed

+90
-21
lines changed

5 files changed

+90
-21
lines changed

cirq-core/cirq/circuits/circuit.py

+3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ def moments(self) -> Sequence['cirq.Moment']:
125125
def device(self) -> 'cirq.Device':
126126
pass
127127

128+
# This is going away once device deprecation is finished.
129+
_device = None # type: devices.Device
130+
128131
def freeze(self) -> 'cirq.FrozenCircuit':
129132
"""Creates a FrozenCircuit from this circuit.
130133

cirq-pasqal/cirq_pasqal/pasqal_device_test.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ def with_qubits(self, *new_qubits):
164164

165165
def test_validate_operation_errors():
166166
d = generic_device(3)
167-
circuit = cirq.Circuit(device=d)
168167

169168
with pytest.raises(ValueError, match="Unsupported operation"):
170169
d.validate_operation(cirq.NamedQubit('q0'))
@@ -178,15 +177,20 @@ def test_validate_operation_errors():
178177
with pytest.raises(ValueError, match="is not part of the device."):
179178
d.validate_operation(cirq.X.on(cirq.NamedQubit('q6')))
180179

180+
d = square_virtual_device(control_r=1.0, num_qubits=3)
181+
with pytest.raises(ValueError, match="are too far away"):
182+
d.validate_operation(cirq.CZ.on(TwoDQubit(0, 0), TwoDQubit(2, 2)))
183+
184+
185+
def test_validate_operation_errors_deprecated():
186+
d = generic_device(3)
187+
circuit = cirq.Circuit()
188+
circuit._device = d
181189
with pytest.raises(
182190
NotImplementedError, match="Measurements on Pasqal devices don't support invert_mask."
183191
):
184192
circuit.append(cirq.measure(*d.qubits, invert_mask=(True, False, False)))
185193

186-
d = square_virtual_device(control_r=1.0, num_qubits=3)
187-
with pytest.raises(ValueError, match="are too far away"):
188-
d.validate_operation(cirq.CZ.on(TwoDQubit(0, 0), TwoDQubit(2, 2)))
189-
190194

191195
def test_validate_moment():
192196
d = square_virtual_device(control_r=1.0, num_qubits=2)
@@ -202,7 +206,7 @@ def test_validate_moment():
202206

203207
def test_validate_circuit():
204208
d = generic_device(2)
205-
circuit1 = cirq.Circuit(device=d)
209+
circuit1 = cirq.Circuit()
206210
circuit1.append(cirq.X(cirq.NamedQubit('q1')))
207211
circuit1.append(cirq.measure(cirq.NamedQubit('q1')))
208212
d.validate_circuit(circuit1)

cirq-pasqal/cirq_pasqal/pasqal_noise_model_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_noisy_moments():
4242
circuit = cirq.Circuit()
4343
circuit.append(cirq.ops.CZ(p_qubits[0], p_qubits[1]))
4444
circuit.append(cirq.ops.Z(p_qubits[1]))
45-
p_circuit = cirq.Circuit(circuit, device=p_device)
45+
p_circuit = cirq.Circuit(circuit)
4646

4747
n_mts = []
4848
for moment in p_circuit._moments:
@@ -65,7 +65,7 @@ def test_default_noise():
6565
circuit = cirq.Circuit()
6666
Gate_l = cirq.ops.CZPowGate(exponent=2)
6767
circuit.append(Gate_l.on(p_qubits[0], p_qubits[1]))
68-
p_circuit = cirq.Circuit(circuit, device=p_device)
68+
p_circuit = cirq.Circuit(circuit)
6969
n_mts = []
7070
for moment in p_circuit._moments:
7171
n_mts.append(noise_model.noisy_moment(moment, p_qubits))

cirq-pasqal/cirq_pasqal/pasqal_sampler.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@
2121

2222

2323
class PasqalSampler(cirq.work.Sampler):
24-
def __init__(self, remote_host: str, access_token: str = '') -> None:
24+
def __init__(
25+
self, remote_host: str, access_token: str = '', device: cirq_pasqal.PasqalDevice = None
26+
) -> None:
2527
"""Inits PasqalSampler.
2628
2729
Args:
2830
remote_host: Address of the remote device.
2931
access_token: Access token for the remote api.
32+
device: Optional cirq_pasqal.PasqalDevice to use with
33+
the sampler.
3034
"""
3135
self.remote_host = remote_host
3236
self._authorization_header = {"Authorization": access_token}
37+
self._device = device
3338

3439
def _serialize_circuit(
3540
self,
@@ -100,6 +105,20 @@ def _send_serialized_circuit(
100105

101106
return result
102107

108+
@cirq._compat.deprecated_parameter(
109+
deadline='v0.15',
110+
fix='The program.device component is going away.'
111+
'Attaching a device to PasqalSampler is now done in __init__.',
112+
parameter_desc='program',
113+
match=lambda args, kwargs: (
114+
len(args) >= 2
115+
and isinstance(args[1], cirq.AbstractCircuit)
116+
and args[1]._device != cirq.UNCONSTRAINED_DEVICE
117+
)
118+
or 'program' in kwargs
119+
and isinstance(kwargs['program'], cirq.AbstractCircuit)
120+
and kwargs['program']._device != cirq.UNCONSTRAINED_DEVICE,
121+
)
103122
def run_sweep(
104123
self, program: cirq.AbstractCircuit, params: cirq.study.Sweepable, repetitions: int = 1
105124
) -> List[cirq.study.Result]:
@@ -114,8 +133,11 @@ def run_sweep(
114133
Result list for this run; one for each possible parameter
115134
resolver.
116135
"""
117-
assert isinstance(program.device, cirq_pasqal.PasqalDevice)
118-
program.device.validate_circuit(program)
136+
device = program._device if program._device != cirq.UNCONSTRAINED_DEVICE else self._device
137+
assert isinstance(
138+
device, cirq_pasqal.PasqalDevice
139+
), "Device must inherit from cirq.PasqalDevice."
140+
device.validate_circuit(program)
119141
trial_results = []
120142

121143
for param_resolver in cirq.study.to_resolvers(params):

cirq-pasqal/cirq_pasqal/pasqal_sampler_test.py

+50-10
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,19 @@ def text(self):
3636
return self.json
3737

3838

39-
def _make_sampler() -> cirq_pasqal.PasqalSampler:
39+
def _make_sampler(device) -> cirq_pasqal.PasqalSampler:
4040

41-
sampler = cirq_pasqal.PasqalSampler(remote_host='http://00.00.00/', access_token='N/A')
41+
sampler = cirq_pasqal.PasqalSampler(
42+
remote_host='http://00.00.00/', access_token='N/A', device=device
43+
)
4244
return sampler
4345

4446

4547
def test_pasqal_circuit_init():
4648
qs = cirq.NamedQubit.range(3, prefix='q')
4749
ex_circuit = cirq.Circuit()
4850
ex_circuit.append([[cirq.CZ(qs[i], qs[i + 1]), cirq.X(qs[i + 1])] for i in range(len(qs) - 1)])
49-
device = cirq_pasqal.PasqalDevice(qubits=qs)
50-
test_circuit = cirq.Circuit(device=device)
51+
test_circuit = cirq.Circuit()
5152
test_circuit.append(
5253
[[cirq.CZ(qs[i], qs[i + 1]), cirq.X(qs[i + 1])] for i in range(len(qs) - 1)]
5354
)
@@ -74,22 +75,22 @@ def test_run_sweep(mock_post, mock_get):
7475
binary = bin(num)[2:].zfill(9)
7576

7677
device = cirq_pasqal.PasqalVirtualDevice(control_radius=1, qubits=qs)
77-
ex_circuit = cirq.Circuit(device=device)
78+
ex_circuit = cirq.Circuit()
7879

7980
for i, b in enumerate(binary[:-1]):
8081
if b == '1':
8182
ex_circuit.append(cirq.X(qs[-i - 1]), strategy=cirq.InsertStrategy.NEW)
8283

8384
ex_circuit_odd = copy.deepcopy(ex_circuit)
84-
ex_circuit_odd.append(cirq.X(qs[0]))
85-
ex_circuit_odd.append(cirq.measure(*qs))
85+
ex_circuit_odd.append(cirq.X(qs[0]), strategy=cirq.InsertStrategy.NEW)
86+
ex_circuit_odd.append(cirq.measure(*qs), strategy=cirq.InsertStrategy.NEW)
8687

8788
xpow = cirq.XPowGate(exponent=par)
88-
ex_circuit.append([xpow(qs[0])])
89-
ex_circuit.append(cirq.measure(*qs))
89+
ex_circuit.append([xpow(qs[0])], strategy=cirq.InsertStrategy.NEW)
90+
ex_circuit.append(cirq.measure(*qs), strategy=cirq.InsertStrategy.NEW)
9091

9192
mock_get.return_value = MockGet(cirq.to_json(ex_circuit_odd))
92-
sampler = _make_sampler()
93+
sampler = _make_sampler(device)
9394

9495
with pytest.raises(ValueError, match="Non-empty moment after measurement"):
9596
wrong_circuit = copy.deepcopy(ex_circuit)
@@ -102,3 +103,42 @@ def test_run_sweep(mock_post, mock_get):
102103
assert cirq.read_json(json_text=submitted_json) == ex_circuit_odd
103104
assert mock_post.call_count == 2
104105
assert data[1] == ex_circuit_odd
106+
107+
108+
@patch('cirq_pasqal.pasqal_sampler.requests.get')
109+
@patch('cirq_pasqal.pasqal_sampler.requests.post')
110+
def test_run_sweep_device_deprecated(mock_post, mock_get):
111+
"""Test running a sweep.
112+
113+
Encodes a random binary number in the qubits, sweeps between odd and even
114+
without noise and checks if the results match.
115+
"""
116+
117+
qs = [cirq_pasqal.ThreeDQubit(i, j, 0) for i in range(3) for j in range(3)]
118+
119+
par = sympy.Symbol('par')
120+
sweep = cirq.Linspace(key='par', start=0.0, stop=1.0, length=2)
121+
122+
num = np.random.randint(0, 2 ** 9)
123+
binary = bin(num)[2:].zfill(9)
124+
125+
device = cirq_pasqal.PasqalVirtualDevice(control_radius=1, qubits=qs)
126+
ex_circuit = cirq.Circuit()
127+
128+
for i, b in enumerate(binary[:-1]):
129+
if b == '1':
130+
ex_circuit.append(cirq.X(qs[-i - 1]), strategy=cirq.InsertStrategy.NEW)
131+
132+
ex_circuit_odd = copy.deepcopy(ex_circuit)
133+
ex_circuit_odd.append(cirq.X(qs[0]), strategy=cirq.InsertStrategy.NEW)
134+
ex_circuit_odd.append(cirq.measure(*qs), strategy=cirq.InsertStrategy.NEW)
135+
136+
xpow = cirq.XPowGate(exponent=par)
137+
ex_circuit.append([xpow(qs[0])], strategy=cirq.InsertStrategy.NEW)
138+
ex_circuit.append(cirq.measure(*qs), strategy=cirq.InsertStrategy.NEW)
139+
140+
mock_get.return_value = MockGet(cirq.to_json(ex_circuit_odd))
141+
sampler = _make_sampler(device)
142+
ex_circuit._device = device
143+
with cirq.testing.assert_deprecated('The program.device component', deadline='v0.15'):
144+
_ = sampler.run_sweep(program=ex_circuit, params=sweep, repetitions=1)

0 commit comments

Comments
 (0)