Skip to content

Increment requirement to Cirq to 0.13.1 #621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5c4bbe4
Increment requirement to Cirq to 0.12.0
tonybruguier Aug 19, 2021
f2f4210
Only depend on cirq-core and cirq-google
tonybruguier Aug 25, 2021
ab02711
Remove extra line
tonybruguier Aug 25, 2021
f3a7289
Bump proto buf version too
tonybruguier Aug 25, 2021
863d1f1
Revert bump in protobufs
tonybruguier Aug 28, 2021
ac5a63a
Merge branch 'master' of github.com:tensorflow/quantum into tfq_bump_…
tonybruguier Sep 25, 2021
266fb97
Try Cirq version 0.13.0 instead
tonybruguier Oct 15, 2021
ac83ceb
Merge branch 'master' of github.com:tensorflow/quantum into tfq_bump_…
tonybruguier Oct 15, 2021
3982b06
Bump protobuf version
tonybruguier Oct 15, 2021
3b189b9
Also bump proto req in setup.py
tonybruguier Oct 15, 2021
c7d0639
Modify setup.py again
tonybruguier Oct 15, 2021
725b3f8
Format code
tonybruguier Oct 16, 2021
4868830
Only a comment
tonybruguier Oct 16, 2021
63ad58c
Try again
tonybruguier Oct 16, 2021
46154c5
Call parent's controlled_by() as a work-around.
tonybruguier Oct 16, 2021
258123a
Disable some lint warnings
tonybruguier Oct 16, 2021
6cb3c3f
Other approach
tonybruguier Oct 16, 2021
6758e10
Do not control if no qubit to control with
tonybruguier Oct 17, 2021
ee6b2c8
Attempt to fix failing tests. Not sure about it.
tonybruguier Oct 17, 2021
808f84a
Add TODO
tonybruguier Oct 17, 2021
2ffac15
Fix incorrect syntax
tonybruguier Oct 17, 2021
d592d5c
Attempt to fix the tests
tonybruguier Oct 18, 2021
9177426
Add docstring
tonybruguier Oct 18, 2021
6405fa9
Merge branch 'master' of github.com:tensorflow/quantum into tfq_bump_…
tonybruguier Oct 21, 2021
d8a1846
Add reference to issue
tonybruguier Oct 21, 2021
a28f7ba
Merge branch 'master' of github.com:tensorflow/quantum into tfq_bump_…
tonybruguier Oct 21, 2021
9d4f5c4
Bump to cirq v.0.13.1
tonybruguier Oct 26, 2021
8bb43fc
Use deterministic proto serialization
tonybruguier Nov 2, 2021
65f4fda
Add back new lines
tonybruguier Nov 2, 2021
a94fb43
lints
tonybruguier Nov 2, 2021
8138c04
Correct comment
tonybruguier Nov 2, 2021
e93afc2
Add deterministic to util_test.py
tonybruguier Nov 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions release/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def finalize_options(self):


REQUIRED_PACKAGES = [
'cirq == 0.11.0', 'sympy == 1.8', 'googleapis-common-protos==1.52.0',
'google-api-core==1.21.0', 'google-auth==1.18.0', 'protobuf==3.13.0'
'cirq-core==0.13.1', 'cirq-google==0.13.1', 'sympy == 1.8',
'googleapis-common-protos==1.52.0', 'google-api-core==1.21.0',
'google-auth==1.18.0', 'protobuf==3.17.3'
]

# placed as extra to not have required overwrite existing nightly installs if
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cirq==0.11.0
cirq-core==0.13.1
cirq-google==0.13.1
sympy==1.8
numpy==1.19.5 # TensorFlow can detect if it was built against other versions.
nbconvert==5.6.1
Expand All @@ -12,4 +13,4 @@ google-api-core==1.21.0
google-auth==1.18.0
google-api-python-client==1.8.0
grpcio==1.34.1
protobuf==3.13.0
protobuf==3.17.3
7 changes: 5 additions & 2 deletions tensorflow_quantum/core/ops/tfq_utility_ops_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ def test_append_circuit(self, max_n_bits, symbols, n_circuits):
cirq_results = [
a + b for a, b in zip(base_circuits, circuits_to_append)
]
self.assertAllEqual(util.convert_to_tensor(tfq_results),
util.convert_to_tensor(cirq_results))
self.assertAllEqual(
util.convert_to_tensor(tfq_results,
deterministic_proto_serialize=True),
util.convert_to_tensor(cirq_results,
deterministic_proto_serialize=True))

@parameterized.parameters([{
'padded_array': [[[1, 0, 0, 0], [1, 1, 1, 1]],
Expand Down
12 changes: 10 additions & 2 deletions tensorflow_quantum/core/serialize/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,16 @@ def _qid_shape_(self):
# pylint: disable=invalid-name
def on(self, *qubits):
"""Returns gate_callable on qubits controlled by contol_qubits."""
return self._gate_callable(*qubits).controlled_by(
*self._control_qubits, control_values=self._control_values)
gate = self._gate_callable(*qubits)
# TODO(tonybruguier,#636): Here we call the parent's class controlled_by
# because Cirq's breaking change #4167 created 3-qubit gates that cannot
# be serialized yet. Instead, support 3-qubit gates and revert the
# work-around.
if len(self._control_qubits) == 0:
return gate
return cirq.ControlledOperation(self._control_qubits,
gate,
control_values=self._control_values)

# pylint: enable=invalid-name

Expand Down
41 changes: 26 additions & 15 deletions tensorflow_quantum/core/serialize/serializer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ def _make_controlled_circuit(circuit, control_qubits, control_values):
for op in moment:
new_op = op
for qb, v in zip(control_qubits[::-1], control_values[::-1]):
new_op = new_op.controlled_by(qb, control_values=[v])
# TODO(tonybruguier,#636): Here we call the parent's class
# controlled_by because Cirq's breaking change #4167 created
# 3-qubit gates that cannot be serialized yet. Instead, support
# 3-qubit gates and revert the work-around.
new_op = cirq.ControlledOperation([qb],
new_op,
control_values=[v])
new_circuit += new_op
return new_circuit

Expand Down Expand Up @@ -404,39 +410,44 @@ def _get_valid_pauli_proto_pairs():
def _get_noise_proto_pairs():
q0 = cirq.GridQubit(0, 0)

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

# Asymmetric depolarization.
(cirq.Circuit(
cirq.asymmetric_depolarize(p_x=0.1, p_y=0.2, p_z=0.3)(q0)),
_build_op_proto("ADP", ['p_x', 'p_y', 'p_z'], [0.1, 0.2, 0.3],
cirq.asymmetric_depolarize(p_x=0.125, p_y=0.25, p_z=0.5)(q0)),
_build_op_proto("ADP", ['p_x', 'p_y', 'p_z'], [0.125, 0.25, 0.5],
['0_0'])),

# Generalized Amplitude damp.
(cirq.Circuit(cirq.generalized_amplitude_damp(p=0.1, gamma=0.2)(q0)),
_build_op_proto("GAD", ['p', 'gamma'], [0.1, 0.2], ['0_0'])),
(cirq.Circuit(cirq.generalized_amplitude_damp(p=0.125, gamma=0.25)(q0)),
_build_op_proto("GAD", ['p', 'gamma'], [0.125, 0.25], ['0_0'])),

# Amplitude damp.
(cirq.Circuit(cirq.amplitude_damp(gamma=0.1)(q0)),
_build_op_proto("AD", ['gamma'], [0.1], ['0_0'])),
(cirq.Circuit(cirq.amplitude_damp(gamma=0.125)(q0)),
_build_op_proto("AD", ['gamma'], [0.125], ['0_0'])),

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

# Phase damp.
(cirq.Circuit(cirq.phase_damp(gamma=0.1)(q0)),
_build_op_proto("PD", ['gamma'], [0.1], ['0_0'])),
(cirq.Circuit(cirq.phase_damp(gamma=0.125)(q0)),
_build_op_proto("PD", ['gamma'], [0.125], ['0_0'])),

# Phase flip.
(cirq.Circuit(cirq.phase_flip(p=0.1)(q0)),
_build_op_proto("PF", ['p'], [0.1], ['0_0'])),
(cirq.Circuit(cirq.phase_flip(p=0.125)(q0)),
_build_op_proto("PF", ['p'], [0.125], ['0_0'])),

# Bit flip.
(cirq.Circuit(cirq.bit_flip(p=0.1)(q0)),
_build_op_proto("BF", ['p'], [0.1], ['0_0']))
(cirq.Circuit(cirq.bit_flip(p=0.125)(q0)),
_build_op_proto("BF", ['p'], [0.125], ['0_0']))
]
return pairs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,20 @@ def test_addcircuit_modify(self):
circuit_b = cirq.testing.random_circuit(bits, 10, 0.9,
util.get_supported_gates())

expected_append = util.convert_to_tensor([circuit_a + circuit_b])
expected_prepend = util.convert_to_tensor([circuit_b + circuit_a])
expected_append = util.convert_to_tensor(
[circuit_a + circuit_b], deterministic_proto_serialize=True)
expected_prepend = util.convert_to_tensor(
[circuit_b + circuit_a], deterministic_proto_serialize=True)

append_layer = elementary.AddCircuit()
prepend_layer = elementary.AddCircuit()

actual_append = util.convert_to_tensor(
util.from_tensor(append_layer(circuit_a, append=circuit_b)))
util.from_tensor(append_layer(circuit_a, append=circuit_b)),
deterministic_proto_serialize=True)
actual_prepend = util.convert_to_tensor(
util.from_tensor(prepend_layer(circuit_a, prepend=circuit_b)))
util.from_tensor(prepend_layer(circuit_a, prepend=circuit_b)),
deterministic_proto_serialize=True)

self.assertEqual(expected_append.numpy()[0], actual_append.numpy()[0])
self.assertEqual(expected_prepend.numpy()[0], actual_prepend.numpy()[0])
Expand Down
26 changes: 21 additions & 5 deletions tensorflow_quantum/python/layers/circuit_executors/input_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
from tensorflow_quantum.python import util


def expand_circuits(inputs, symbol_names=None, symbol_values=None):
def expand_circuits(inputs,
symbol_names=None,
symbol_values=None,
deterministic_proto_serialize=False):
"""Function for consistently expanding circuit inputs.

Args:
Expand All @@ -33,6 +36,8 @@ def expand_circuits(inputs, symbol_names=None, symbol_values=None):
parameterizing the input circuits.
symbol_values: a Python `list`, `tuple`, or `numpy.ndarray` of
floating point values, or `tf.Tensor` of dtype `float32`.
deterministic_proto_serialize: Whether to use a deterministic proto
serialization.

Returns:
inputs: `tf.Tensor` of dtype `string` with shape [batch_size]
Expand Down Expand Up @@ -80,11 +85,16 @@ def expand_circuits(inputs, symbol_names=None, symbol_values=None):
# Ingest and promote circuit.
if isinstance(inputs, cirq.Circuit):
# process single circuit.
inputs = tf.tile(util.convert_to_tensor([inputs]), [symbol_batch_dim])
inputs = tf.tile(
util.convert_to_tensor(
[inputs],
deterministic_proto_serialize=deterministic_proto_serialize),
[symbol_batch_dim])

elif isinstance(inputs, (list, tuple, np.ndarray)):
# process list of circuits.
inputs = util.convert_to_tensor(inputs)
inputs = util.convert_to_tensor(
inputs, deterministic_proto_serialize=deterministic_proto_serialize)

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


def expand_operators(operators=None, circuit_batch_dim=1):
def expand_operators(operators=None,
circuit_batch_dim=1,
deterministic_proto_serialize=False):
"""Check and expand operators.

Args:
Expand All @@ -112,6 +124,8 @@ def expand_operators(operators=None, circuit_batch_dim=1):
or `cirq.PauliSum`s; or pre-converted `tf.Tensor` of
`cirq.PauliString`s or `cirq.PauliSum`s.
circuit_batch_dim: number of circuits in the final expansion
deterministic_proto_serialize: Whether to use a deterministic proto
serialization.

Returns:
operators: `tf.Tensor` of dtype `string` with shape [batch_size, n_ops]
Expand All @@ -136,7 +150,9 @@ def expand_operators(operators=None, circuit_batch_dim=1):
# to match the batch size of circuits.
operators = [operators]
op_needs_tile = True
operators = util.convert_to_tensor(operators)
operators = util.convert_to_tensor(
operators,
deterministic_proto_serialize=deterministic_proto_serialize)

if op_needs_tile:
# Don't tile up if the user gave a python list that was precisely
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def test_expand_circuits_error(self):
names_tensor = tf.convert_to_tensor([str(symbol)],
dtype=tf.dtypes.string)
circuit_tensor = util.convert_to_tensor(
[cirq.Circuit(cirq.H(qubit)**symbol)])
[cirq.Circuit(cirq.H(qubit)**symbol)],
deterministic_proto_serialize=True)
values_tensor = tf.convert_to_tensor([[0.5]], dtype=tf.dtypes.float32)

# Bad circuit arg
Expand Down Expand Up @@ -89,7 +90,8 @@ def test_allowed_cases(self):
cirq.X(qubits[1])**names_symbol_list[1])
circuit_list = [circuit_alone for _ in range(3)]
circuit_tuple = tuple(circuit_list)
circuit_tensor = util.convert_to_tensor(circuit_list)
circuit_tensor = util.convert_to_tensor(
circuit_list, deterministic_proto_serialize=True)
values_list = [[1], [2], [3]]
values_tuple = tuple(values_list)
values_ndarray = np.array(values_list)
Expand All @@ -106,7 +108,8 @@ def test_allowed_cases(self):
values_list, values_tuple, values_ndarray, values_tensor
]:
circuit_test, names_test, values_test = \
input_checks.expand_circuits(circuit, names, values)
input_checks.expand_circuits(circuit, names, values, \
deterministic_proto_serialize=True)
self.assertAllEqual(circuit_test, circuit_tensor)
self.assertAllEqual(names_test, names_tensor)
self.assertAllEqual(values_test, values_tensor)
Expand All @@ -116,7 +119,8 @@ def test_allowed_cases(self):
values_tensor = tf.convert_to_tensor([[]] * 3, dtype=tf.dtypes.float32)
for circuit in [circuit_list, circuit_tuple, circuit_tensor]:
circuit_test, names_test, values_test = \
input_checks.expand_circuits(circuit)
input_checks.expand_circuits(circuit, \
deterministic_proto_serialize=True)
self.assertAllEqual(circuit_test, circuit_tensor)
self.assertAllEqual(names_test, names_tensor)
self.assertAllEqual(values_test, values_tensor)
Expand All @@ -143,13 +147,15 @@ def test_allowed_cases(self):
bare_tuple = tuple(bare_list)
shaped_list = [[bare_string]] * batch_dim
shaped_tuple = tuple(shaped_list)
op_tensor_single = util.convert_to_tensor([[bare_string]])
op_tensor_single = util.convert_to_tensor(
[[bare_string]], deterministic_proto_serialize=True)
op_tensor = tf.tile(op_tensor_single, [batch_dim, 1])
for op in [
bare_string, bare_sum, bare_list, bare_tuple, shaped_list,
shaped_tuple, op_tensor
]:
op_test = input_checks.expand_operators(op, batch_dim)
op_test = input_checks.expand_operators(
op, batch_dim, deterministic_proto_serialize=True)
self.assertAllEqual(op_test, op_tensor)


Expand Down
15 changes: 11 additions & 4 deletions tensorflow_quantum/python/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ def _apply_random_control(gate, all_qubits):
return gate
control_locs = random.sample(open_qubits, n_open)
control_values = random.choices([0, 1], k=n_open)
return gate.controlled_by(*control_locs, control_values=control_values)
# TODO(tonybruguier,#636): Here we call the parent's class controlled_by
# because Cirq's breaking change #4167 created 3-qubit gates that cannot be
# serialized yet. Instead, support 3-qubit gates and revert the work-around.
return cirq.ControlledOperation(control_locs, gate, control_values)


def random_symbol_circuit(qubits,
Expand Down Expand Up @@ -258,7 +261,7 @@ def random_pauli_sums(qubits, max_sum_length, n_sums):

# There are no native convertible ops inside of this function.
@tf.autograph.experimental.do_not_convert
def convert_to_tensor(items_to_convert):
def convert_to_tensor(items_to_convert, deterministic_proto_serialize=False):
"""Convert lists of tfq supported primitives to tensor representations.

Recursively convert a nested lists of `cirq.PauliSum` or `cirq.Circuit`
Expand Down Expand Up @@ -290,6 +293,8 @@ def convert_to_tensor(items_to_convert):
Args:
items_to_convert: Python `list` or nested `list` of `cirq.Circuit`
or `cirq.Paulisum` objects. Must be recangular.
deterministic_proto_serialize: Whether to use a deterministic
serialization when calling SerializeToString().
Returns:
A `tf.Tensor` that represents the input items.

Expand All @@ -310,12 +315,14 @@ def recur(items_to_convert, curr_type=None):
not curr_type == cirq.Circuit:
curr_type = cirq.PauliSum
tensored_items.append(
serializer.serialize_paulisum(item).SerializeToString())
serializer.serialize_paulisum(item).SerializeToString(
deterministic=deterministic_proto_serialize))
elif isinstance(item, cirq.Circuit) and\
not curr_type == cirq.PauliSum:
curr_type = cirq.Circuit
tensored_items.append(
serializer.serialize_circuit(item).SerializeToString())
serializer.serialize_circuit(item).SerializeToString(
deterministic=deterministic_proto_serialize))
else:
raise TypeError("Incompatible item passed into "
"convert_to_tensor. Tensor detected type: {}. "
Expand Down
27 changes: 17 additions & 10 deletions tensorflow_quantum/python/util_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ def _single_to_tensor(item):
raise TypeError("Item must be a Circuit or PauliSum. Got {}.".format(
type(item)))
if isinstance(item, (cirq.PauliSum, cirq.PauliString)):
return serializer.serialize_paulisum(item).SerializeToString()
return serializer.serialize_circuit(item).SerializeToString()
return serializer.serialize_paulisum(item).SerializeToString(
deterministic=True)
return serializer.serialize_circuit(item).SerializeToString(
deterministic=True)


def _exponential(theta, op):
Expand Down Expand Up @@ -79,12 +81,14 @@ def test_convert_to_tensor(self, item):
"""Test that the convert_to_tensor function works correctly by manually
serializing flat and 2-deep nested lists of Circuits and PauliSums."""
nested = [[item, item]] * 2
nested_actual = util.convert_to_tensor(nested)
nested_actual = util.convert_to_tensor(
nested, deterministic_proto_serialize=True)
nested_expected = np.array(
[np.array([_single_to_tensor(x) for x in row]) for row in nested])
self.assertAllEqual(nested_actual, nested_expected)
flat = [item, item]
flat_actual = util.convert_to_tensor(flat)
flat_actual = util.convert_to_tensor(flat,
deterministic_proto_serialize=True)
flat_expected = np.array([_single_to_tensor(x) for x in flat])
self.assertAllEqual(flat_actual, flat_expected)

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

item_nested_tensorized = util.convert_to_tensor([[item, item],
[item, item]])
item_flat_tensorized = util.convert_to_tensor([item, item])
item_nested_tensorized = util.convert_to_tensor(
[[item, item], [item, item]], deterministic_proto_serialize=True)
item_flat_tensorized = util.convert_to_tensor(
[item, item], deterministic_proto_serialize=True)
item_nested_cycled = util.convert_to_tensor(
util.from_tensor(item_nested_tensorized))
util.from_tensor(item_nested_tensorized),
deterministic_proto_serialize=True)

self.assertAllEqual(item_nested_tensorized, item_nested_cycled)
item_flat_cycled = util.convert_to_tensor(
util.from_tensor(item_flat_tensorized))
util.from_tensor(item_flat_tensorized),
deterministic_proto_serialize=True)
self.assertAllEqual(item_flat_tensorized, item_flat_cycled)

def test_from_tensor_errors(self):
Expand Down Expand Up @@ -570,7 +577,7 @@ def test_serializability(self):
op1 = theta * cirq.Z(q[0]) * cirq.Z(q[1])
op2 = theta * identity
circuit = util.exponential(operators=[op1, op2])
util.convert_to_tensor([circuit])
util.convert_to_tensor([circuit], deterministic_proto_serialize=True)


if __name__ == "__main__":
Expand Down