Skip to content

Commit 2706655

Browse files
authored
Increment requirement to Cirq to 0.13.1 (#621)
* Increment requirement to Cirq to 0.12.0 * Only depend on cirq-core and cirq-google * Remove extra line * Bump proto buf version too * Revert bump in protobufs * Try Cirq version 0.13.0 instead * Bump protobuf version * Also bump proto req in setup.py * Modify setup.py again * Format code * Only a comment * Try again * Call parent's controlled_by() as a work-around. * Disable some lint warnings * Other approach * Do not control if no qubit to control with * Attempt to fix failing tests. Not sure about it. * Add TODO * Fix incorrect syntax * Attempt to fix the tests * Add docstring * Add reference to issue * Bump to cirq v.0.13.1 * Use deterministic proto serialization * Add back new lines * lints * Correct comment * Add deterministic to util_test.py
1 parent 3344433 commit 2706655

File tree

10 files changed

+116
-52
lines changed

10 files changed

+116
-52
lines changed

release/setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ def finalize_options(self):
5151

5252

5353
REQUIRED_PACKAGES = [
54-
'cirq == 0.11.0', 'sympy == 1.8', 'googleapis-common-protos==1.52.0',
55-
'google-api-core==1.21.0', 'google-auth==1.18.0', 'protobuf==3.13.0'
54+
'cirq-core==0.13.1', 'cirq-google==0.13.1', 'sympy == 1.8',
55+
'googleapis-common-protos==1.52.0', 'google-api-core==1.21.0',
56+
'google-auth==1.18.0', 'protobuf==3.17.3'
5657
]
5758

5859
# placed as extra to not have required overwrite existing nightly installs if

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
cirq==0.11.0
1+
cirq-core==0.13.1
2+
cirq-google==0.13.1
23
sympy==1.8
34
numpy==1.19.5 # TensorFlow can detect if it was built against other versions.
45
nbconvert==5.6.1
@@ -12,4 +13,4 @@ google-api-core==1.21.0
1213
google-auth==1.18.0
1314
google-api-python-client==1.8.0
1415
grpcio==1.34.1
15-
protobuf==3.13.0
16+
protobuf==3.17.3

tensorflow_quantum/core/ops/tfq_utility_ops_test.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,11 @@ def test_append_circuit(self, max_n_bits, symbols, n_circuits):
117117
cirq_results = [
118118
a + b for a, b in zip(base_circuits, circuits_to_append)
119119
]
120-
self.assertAllEqual(util.convert_to_tensor(tfq_results),
121-
util.convert_to_tensor(cirq_results))
120+
self.assertAllEqual(
121+
util.convert_to_tensor(tfq_results,
122+
deterministic_proto_serialize=True),
123+
util.convert_to_tensor(cirq_results,
124+
deterministic_proto_serialize=True))
122125

123126
@parameterized.parameters([{
124127
'padded_array': [[[1, 0, 0, 0], [1, 1, 1, 1]],

tensorflow_quantum/core/serialize/serializer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,16 @@ def _qid_shape_(self):
144144
# pylint: disable=invalid-name
145145
def on(self, *qubits):
146146
"""Returns gate_callable on qubits controlled by contol_qubits."""
147-
return self._gate_callable(*qubits).controlled_by(
148-
*self._control_qubits, control_values=self._control_values)
147+
gate = self._gate_callable(*qubits)
148+
# TODO(tonybruguier,#636): Here we call the parent's class controlled_by
149+
# because Cirq's breaking change #4167 created 3-qubit gates that cannot
150+
# be serialized yet. Instead, support 3-qubit gates and revert the
151+
# work-around.
152+
if len(self._control_qubits) == 0:
153+
return gate
154+
return cirq.ControlledOperation(self._control_qubits,
155+
gate,
156+
control_values=self._control_values)
149157

150158
# pylint: enable=invalid-name
151159

tensorflow_quantum/core/serialize/serializer_test.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,13 @@ def _make_controlled_circuit(circuit, control_qubits, control_values):
121121
for op in moment:
122122
new_op = op
123123
for qb, v in zip(control_qubits[::-1], control_values[::-1]):
124-
new_op = new_op.controlled_by(qb, control_values=[v])
124+
# TODO(tonybruguier,#636): Here we call the parent's class
125+
# controlled_by because Cirq's breaking change #4167 created
126+
# 3-qubit gates that cannot be serialized yet. Instead, support
127+
# 3-qubit gates and revert the work-around.
128+
new_op = cirq.ControlledOperation([qb],
129+
new_op,
130+
control_values=[v])
125131
new_circuit += new_op
126132
return new_circuit
127133

@@ -404,39 +410,44 @@ def _get_valid_pauli_proto_pairs():
404410
def _get_noise_proto_pairs():
405411
q0 = cirq.GridQubit(0, 0)
406412

413+
# NOTE(tonybruguier): All the parameters are powers of 2. This is because
414+
# Python only uses double, which means that Protobufs use double even if the
415+
# field is a float. However, the serialization sometimes goes though C++ and
416+
# thus would use float. Thus, we need to have numbers that are exactly
417+
# representable on a float. Powers of 2 are a convenient subset.
407418
pairs = [
408419
# Depolarization.
409-
(cirq.Circuit(cirq.depolarize(p=0.3)(q0)),
410-
_build_op_proto("DP", ['p'], [0.3], ['0_0'])),
420+
(cirq.Circuit(cirq.depolarize(p=0.5)(q0)),
421+
_build_op_proto("DP", ['p'], [0.5], ['0_0'])),
411422

412423
# Asymmetric depolarization.
413424
(cirq.Circuit(
414-
cirq.asymmetric_depolarize(p_x=0.1, p_y=0.2, p_z=0.3)(q0)),
415-
_build_op_proto("ADP", ['p_x', 'p_y', 'p_z'], [0.1, 0.2, 0.3],
425+
cirq.asymmetric_depolarize(p_x=0.125, p_y=0.25, p_z=0.5)(q0)),
426+
_build_op_proto("ADP", ['p_x', 'p_y', 'p_z'], [0.125, 0.25, 0.5],
416427
['0_0'])),
417428

418429
# Generalized Amplitude damp.
419-
(cirq.Circuit(cirq.generalized_amplitude_damp(p=0.1, gamma=0.2)(q0)),
420-
_build_op_proto("GAD", ['p', 'gamma'], [0.1, 0.2], ['0_0'])),
430+
(cirq.Circuit(cirq.generalized_amplitude_damp(p=0.125, gamma=0.25)(q0)),
431+
_build_op_proto("GAD", ['p', 'gamma'], [0.125, 0.25], ['0_0'])),
421432

422433
# Amplitude damp.
423-
(cirq.Circuit(cirq.amplitude_damp(gamma=0.1)(q0)),
424-
_build_op_proto("AD", ['gamma'], [0.1], ['0_0'])),
434+
(cirq.Circuit(cirq.amplitude_damp(gamma=0.125)(q0)),
435+
_build_op_proto("AD", ['gamma'], [0.125], ['0_0'])),
425436

426437
# Reset.
427438
(cirq.Circuit(cirq.reset(q0)), _build_op_proto("RST", [], [], ['0_0'])),
428439

429440
# Phase damp.
430-
(cirq.Circuit(cirq.phase_damp(gamma=0.1)(q0)),
431-
_build_op_proto("PD", ['gamma'], [0.1], ['0_0'])),
441+
(cirq.Circuit(cirq.phase_damp(gamma=0.125)(q0)),
442+
_build_op_proto("PD", ['gamma'], [0.125], ['0_0'])),
432443

433444
# Phase flip.
434-
(cirq.Circuit(cirq.phase_flip(p=0.1)(q0)),
435-
_build_op_proto("PF", ['p'], [0.1], ['0_0'])),
445+
(cirq.Circuit(cirq.phase_flip(p=0.125)(q0)),
446+
_build_op_proto("PF", ['p'], [0.125], ['0_0'])),
436447

437448
# Bit flip.
438-
(cirq.Circuit(cirq.bit_flip(p=0.1)(q0)),
439-
_build_op_proto("BF", ['p'], [0.1], ['0_0']))
449+
(cirq.Circuit(cirq.bit_flip(p=0.125)(q0)),
450+
_build_op_proto("BF", ['p'], [0.125], ['0_0']))
440451
]
441452
return pairs
442453

tensorflow_quantum/python/layers/circuit_construction/elementary_test.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,20 @@ def test_addcircuit_modify(self):
101101
circuit_b = cirq.testing.random_circuit(bits, 10, 0.9,
102102
util.get_supported_gates())
103103

104-
expected_append = util.convert_to_tensor([circuit_a + circuit_b])
105-
expected_prepend = util.convert_to_tensor([circuit_b + circuit_a])
104+
expected_append = util.convert_to_tensor(
105+
[circuit_a + circuit_b], deterministic_proto_serialize=True)
106+
expected_prepend = util.convert_to_tensor(
107+
[circuit_b + circuit_a], deterministic_proto_serialize=True)
106108

107109
append_layer = elementary.AddCircuit()
108110
prepend_layer = elementary.AddCircuit()
109111

110112
actual_append = util.convert_to_tensor(
111-
util.from_tensor(append_layer(circuit_a, append=circuit_b)))
113+
util.from_tensor(append_layer(circuit_a, append=circuit_b)),
114+
deterministic_proto_serialize=True)
112115
actual_prepend = util.convert_to_tensor(
113-
util.from_tensor(prepend_layer(circuit_a, prepend=circuit_b)))
116+
util.from_tensor(prepend_layer(circuit_a, prepend=circuit_b)),
117+
deterministic_proto_serialize=True)
114118

115119
self.assertEqual(expected_append.numpy()[0], actual_append.numpy()[0])
116120
self.assertEqual(expected_prepend.numpy()[0], actual_prepend.numpy()[0])

tensorflow_quantum/python/layers/circuit_executors/input_checks.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
from tensorflow_quantum.python import util
2222

2323

24-
def expand_circuits(inputs, symbol_names=None, symbol_values=None):
24+
def expand_circuits(inputs,
25+
symbol_names=None,
26+
symbol_values=None,
27+
deterministic_proto_serialize=False):
2528
"""Function for consistently expanding circuit inputs.
2629
2730
Args:
@@ -33,6 +36,8 @@ def expand_circuits(inputs, symbol_names=None, symbol_values=None):
3336
parameterizing the input circuits.
3437
symbol_values: a Python `list`, `tuple`, or `numpy.ndarray` of
3538
floating point values, or `tf.Tensor` of dtype `float32`.
39+
deterministic_proto_serialize: Whether to use a deterministic proto
40+
serialization.
3641
3742
Returns:
3843
inputs: `tf.Tensor` of dtype `string` with shape [batch_size]
@@ -80,11 +85,16 @@ def expand_circuits(inputs, symbol_names=None, symbol_values=None):
8085
# Ingest and promote circuit.
8186
if isinstance(inputs, cirq.Circuit):
8287
# process single circuit.
83-
inputs = tf.tile(util.convert_to_tensor([inputs]), [symbol_batch_dim])
88+
inputs = tf.tile(
89+
util.convert_to_tensor(
90+
[inputs],
91+
deterministic_proto_serialize=deterministic_proto_serialize),
92+
[symbol_batch_dim])
8493

8594
elif isinstance(inputs, (list, tuple, np.ndarray)):
8695
# process list of circuits.
87-
inputs = util.convert_to_tensor(inputs)
96+
inputs = util.convert_to_tensor(
97+
inputs, deterministic_proto_serialize=deterministic_proto_serialize)
8898

8999
if not tf.is_tensor(inputs):
90100
raise TypeError("circuits cannot be parsed with given input:"
@@ -100,7 +110,9 @@ def expand_circuits(inputs, symbol_names=None, symbol_values=None):
100110
return inputs, symbol_names, symbol_values
101111

102112

103-
def expand_operators(operators=None, circuit_batch_dim=1):
113+
def expand_operators(operators=None,
114+
circuit_batch_dim=1,
115+
deterministic_proto_serialize=False):
104116
"""Check and expand operators.
105117
106118
Args:
@@ -112,6 +124,8 @@ def expand_operators(operators=None, circuit_batch_dim=1):
112124
or `cirq.PauliSum`s; or pre-converted `tf.Tensor` of
113125
`cirq.PauliString`s or `cirq.PauliSum`s.
114126
circuit_batch_dim: number of circuits in the final expansion
127+
deterministic_proto_serialize: Whether to use a deterministic proto
128+
serialization.
115129
116130
Returns:
117131
operators: `tf.Tensor` of dtype `string` with shape [batch_size, n_ops]
@@ -136,7 +150,9 @@ def expand_operators(operators=None, circuit_batch_dim=1):
136150
# to match the batch size of circuits.
137151
operators = [operators]
138152
op_needs_tile = True
139-
operators = util.convert_to_tensor(operators)
153+
operators = util.convert_to_tensor(
154+
operators,
155+
deterministic_proto_serialize=deterministic_proto_serialize)
140156

141157
if op_needs_tile:
142158
# Don't tile up if the user gave a python list that was precisely

tensorflow_quantum/python/layers/circuit_executors/input_checks_test.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def test_expand_circuits_error(self):
3434
names_tensor = tf.convert_to_tensor([str(symbol)],
3535
dtype=tf.dtypes.string)
3636
circuit_tensor = util.convert_to_tensor(
37-
[cirq.Circuit(cirq.H(qubit)**symbol)])
37+
[cirq.Circuit(cirq.H(qubit)**symbol)],
38+
deterministic_proto_serialize=True)
3839
values_tensor = tf.convert_to_tensor([[0.5]], dtype=tf.dtypes.float32)
3940

4041
# Bad circuit arg
@@ -89,7 +90,8 @@ def test_allowed_cases(self):
8990
cirq.X(qubits[1])**names_symbol_list[1])
9091
circuit_list = [circuit_alone for _ in range(3)]
9192
circuit_tuple = tuple(circuit_list)
92-
circuit_tensor = util.convert_to_tensor(circuit_list)
93+
circuit_tensor = util.convert_to_tensor(
94+
circuit_list, deterministic_proto_serialize=True)
9395
values_list = [[1], [2], [3]]
9496
values_tuple = tuple(values_list)
9597
values_ndarray = np.array(values_list)
@@ -106,7 +108,8 @@ def test_allowed_cases(self):
106108
values_list, values_tuple, values_ndarray, values_tensor
107109
]:
108110
circuit_test, names_test, values_test = \
109-
input_checks.expand_circuits(circuit, names, values)
111+
input_checks.expand_circuits(circuit, names, values, \
112+
deterministic_proto_serialize=True)
110113
self.assertAllEqual(circuit_test, circuit_tensor)
111114
self.assertAllEqual(names_test, names_tensor)
112115
self.assertAllEqual(values_test, values_tensor)
@@ -116,7 +119,8 @@ def test_allowed_cases(self):
116119
values_tensor = tf.convert_to_tensor([[]] * 3, dtype=tf.dtypes.float32)
117120
for circuit in [circuit_list, circuit_tuple, circuit_tensor]:
118121
circuit_test, names_test, values_test = \
119-
input_checks.expand_circuits(circuit)
122+
input_checks.expand_circuits(circuit, \
123+
deterministic_proto_serialize=True)
120124
self.assertAllEqual(circuit_test, circuit_tensor)
121125
self.assertAllEqual(names_test, names_tensor)
122126
self.assertAllEqual(values_test, values_tensor)
@@ -143,13 +147,15 @@ def test_allowed_cases(self):
143147
bare_tuple = tuple(bare_list)
144148
shaped_list = [[bare_string]] * batch_dim
145149
shaped_tuple = tuple(shaped_list)
146-
op_tensor_single = util.convert_to_tensor([[bare_string]])
150+
op_tensor_single = util.convert_to_tensor(
151+
[[bare_string]], deterministic_proto_serialize=True)
147152
op_tensor = tf.tile(op_tensor_single, [batch_dim, 1])
148153
for op in [
149154
bare_string, bare_sum, bare_list, bare_tuple, shaped_list,
150155
shaped_tuple, op_tensor
151156
]:
152-
op_test = input_checks.expand_operators(op, batch_dim)
157+
op_test = input_checks.expand_operators(
158+
op, batch_dim, deterministic_proto_serialize=True)
153159
self.assertAllEqual(op_test, op_tensor)
154160

155161

tensorflow_quantum/python/util.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ def _apply_random_control(gate, all_qubits):
115115
return gate
116116
control_locs = random.sample(open_qubits, n_open)
117117
control_values = random.choices([0, 1], k=n_open)
118-
return gate.controlled_by(*control_locs, control_values=control_values)
118+
# TODO(tonybruguier,#636): Here we call the parent's class controlled_by
119+
# because Cirq's breaking change #4167 created 3-qubit gates that cannot be
120+
# serialized yet. Instead, support 3-qubit gates and revert the work-around.
121+
return cirq.ControlledOperation(control_locs, gate, control_values)
119122

120123

121124
def random_symbol_circuit(qubits,
@@ -258,7 +261,7 @@ def random_pauli_sums(qubits, max_sum_length, n_sums):
258261

259262
# There are no native convertible ops inside of this function.
260263
@tf.autograph.experimental.do_not_convert
261-
def convert_to_tensor(items_to_convert):
264+
def convert_to_tensor(items_to_convert, deterministic_proto_serialize=False):
262265
"""Convert lists of tfq supported primitives to tensor representations.
263266
264267
Recursively convert a nested lists of `cirq.PauliSum` or `cirq.Circuit`
@@ -290,6 +293,8 @@ def convert_to_tensor(items_to_convert):
290293
Args:
291294
items_to_convert: Python `list` or nested `list` of `cirq.Circuit`
292295
or `cirq.Paulisum` objects. Must be recangular.
296+
deterministic_proto_serialize: Whether to use a deterministic
297+
serialization when calling SerializeToString().
293298
Returns:
294299
A `tf.Tensor` that represents the input items.
295300
@@ -310,12 +315,14 @@ def recur(items_to_convert, curr_type=None):
310315
not curr_type == cirq.Circuit:
311316
curr_type = cirq.PauliSum
312317
tensored_items.append(
313-
serializer.serialize_paulisum(item).SerializeToString())
318+
serializer.serialize_paulisum(item).SerializeToString(
319+
deterministic=deterministic_proto_serialize))
314320
elif isinstance(item, cirq.Circuit) and\
315321
not curr_type == cirq.PauliSum:
316322
curr_type = cirq.Circuit
317323
tensored_items.append(
318-
serializer.serialize_circuit(item).SerializeToString())
324+
serializer.serialize_circuit(item).SerializeToString(
325+
deterministic=deterministic_proto_serialize))
319326
else:
320327
raise TypeError("Incompatible item passed into "
321328
"convert_to_tensor. Tensor detected type: {}. "

tensorflow_quantum/python/util_test.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ def _single_to_tensor(item):
2828
raise TypeError("Item must be a Circuit or PauliSum. Got {}.".format(
2929
type(item)))
3030
if isinstance(item, (cirq.PauliSum, cirq.PauliString)):
31-
return serializer.serialize_paulisum(item).SerializeToString()
32-
return serializer.serialize_circuit(item).SerializeToString()
31+
return serializer.serialize_paulisum(item).SerializeToString(
32+
deterministic=True)
33+
return serializer.serialize_circuit(item).SerializeToString(
34+
deterministic=True)
3335

3436

3537
def _exponential(theta, op):
@@ -79,12 +81,14 @@ def test_convert_to_tensor(self, item):
7981
"""Test that the convert_to_tensor function works correctly by manually
8082
serializing flat and 2-deep nested lists of Circuits and PauliSums."""
8183
nested = [[item, item]] * 2
82-
nested_actual = util.convert_to_tensor(nested)
84+
nested_actual = util.convert_to_tensor(
85+
nested, deterministic_proto_serialize=True)
8386
nested_expected = np.array(
8487
[np.array([_single_to_tensor(x) for x in row]) for row in nested])
8588
self.assertAllEqual(nested_actual, nested_expected)
8689
flat = [item, item]
87-
flat_actual = util.convert_to_tensor(flat)
90+
flat_actual = util.convert_to_tensor(flat,
91+
deterministic_proto_serialize=True)
8892
flat_expected = np.array([_single_to_tensor(x) for x in flat])
8993
self.assertAllEqual(flat_actual, flat_expected)
9094

@@ -106,15 +110,18 @@ def test_convert_to_tensor_errors(self):
106110
def test_from_tensor(self, item):
107111
"""Check from_tensor assuming convert_to_tensor works."""
108112

109-
item_nested_tensorized = util.convert_to_tensor([[item, item],
110-
[item, item]])
111-
item_flat_tensorized = util.convert_to_tensor([item, item])
113+
item_nested_tensorized = util.convert_to_tensor(
114+
[[item, item], [item, item]], deterministic_proto_serialize=True)
115+
item_flat_tensorized = util.convert_to_tensor(
116+
[item, item], deterministic_proto_serialize=True)
112117
item_nested_cycled = util.convert_to_tensor(
113-
util.from_tensor(item_nested_tensorized))
118+
util.from_tensor(item_nested_tensorized),
119+
deterministic_proto_serialize=True)
114120

115121
self.assertAllEqual(item_nested_tensorized, item_nested_cycled)
116122
item_flat_cycled = util.convert_to_tensor(
117-
util.from_tensor(item_flat_tensorized))
123+
util.from_tensor(item_flat_tensorized),
124+
deterministic_proto_serialize=True)
118125
self.assertAllEqual(item_flat_tensorized, item_flat_cycled)
119126

120127
def test_from_tensor_errors(self):
@@ -570,7 +577,7 @@ def test_serializability(self):
570577
op1 = theta * cirq.Z(q[0]) * cirq.Z(q[1])
571578
op2 = theta * identity
572579
circuit = util.exponential(operators=[op1, op2])
573-
util.convert_to_tensor([circuit])
580+
util.convert_to_tensor([circuit], deterministic_proto_serialize=True)
574581

575582

576583
if __name__ == "__main__":

0 commit comments

Comments
 (0)