From 13664940f44e1bee9be3bb5129046f1a951c8be9 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Mon, 18 Sep 2023 15:40:27 -0700 Subject: [PATCH 1/2] Apply minor doc fixes (#6289) - quirk_url_to_circuit and quirk_json_to_circuit had weird HTML in them. - concat_ragged had a bunch of pre tags in the output. I believe these changes fix the markdown generation. --- cirq-core/cirq/circuits/circuit.py | 16 ++-- .../cirq/interop/quirk/url_to_circuit.py | 78 ++++++++++--------- .../cirq/protocols/apply_channel_protocol.py | 15 ++-- 3 files changed, 57 insertions(+), 52 deletions(-) diff --git a/cirq-core/cirq/circuits/circuit.py b/cirq-core/cirq/circuits/circuit.py index a0c2fb0d94a..a23e87a2d4a 100644 --- a/cirq-core/cirq/circuits/circuit.py +++ b/cirq-core/cirq/circuits/circuit.py @@ -1465,14 +1465,14 @@ def concat_ragged( Beware that this method is *not* associative. For example: - >>> a, b = cirq.LineQubit.range(2) - >>> A = cirq.Circuit(cirq.H(a)) - >>> B = cirq.Circuit(cirq.H(b)) - >>> f = cirq.Circuit.concat_ragged - >>> f(f(A, B), A) == f(A, f(B, A)) - False - >>> len(f(f(f(A, B), A), B)) == len(f(f(A, f(B, A)), B)) - False + >>> a, b = cirq.LineQubit.range(2) + >>> A = cirq.Circuit(cirq.H(a)) + >>> B = cirq.Circuit(cirq.H(b)) + >>> f = cirq.Circuit.concat_ragged + >>> f(f(A, B), A) == f(A, f(B, A)) + False + >>> len(f(f(f(A, B), A), B)) == len(f(f(A, f(B, A)), B)) + False Args: *circuits: The circuits to concatenate. diff --git a/cirq-core/cirq/interop/quirk/url_to_circuit.py b/cirq-core/cirq/interop/quirk/url_to_circuit.py index 978ac574d18..8c27a44c538 100644 --- a/cirq-core/cirq/interop/quirk/url_to_circuit.py +++ b/cirq-core/cirq/interop/quirk/url_to_circuit.py @@ -77,39 +77,40 @@ def quirk_url_to_circuit( a billion laughs attack in the form of nested custom gates. Examples: - >>> print(cirq.quirk_url_to_circuit( - ... 'http://algassert.com/quirk#circuit={"cols":[["H"],["•","X"]]}' - ... )) - 0: ───H───@─── - │ - 1: ───────X─── - - >>> print(cirq.quirk_url_to_circuit( - ... 'http://algassert.com/quirk#circuit={"cols":[["H"],["•","X"]]}', - ... qubits=[cirq.NamedQubit('Alice'), cirq.NamedQubit('Bob')] - ... )) - Alice: ───H───@─── - │ - Bob: ─────────X─── - - >>> print(cirq.quirk_url_to_circuit( - ... 'http://algassert.com/quirk#circuit={"cols":[["iswap"]]}', - ... extra_cell_makers={'iswap': cirq.ISWAP})) - 0: ───iSwap─── - │ - 1: ───iSwap─── - - >>> print(cirq.quirk_url_to_circuit( - ... 'http://algassert.com/quirk#circuit={"cols":[["iswap"]]}', - ... extra_cell_makers=[ - ... cirq.interop.quirk.cells.CellMaker( - ... identifier='iswap', - ... size=2, - ... maker=lambda args: cirq.ISWAP(*args.qubits)) - ... ])) - 0: ───iSwap─── + + >>> print(cirq.quirk_url_to_circuit( + ... 'http://algassert.com/quirk#circuit={"cols":[["H"],["•","X"]]}' + ... )) + 0: ───H───@─── │ - 1: ───iSwap─── + 1: ───────X─── + + >>> print(cirq.quirk_url_to_circuit( + ... 'http://algassert.com/quirk#circuit={"cols":[["H"],["•","X"]]}', + ... qubits=[cirq.NamedQubit('Alice'), cirq.NamedQubit('Bob')] + ... )) + Alice: ───H───@─── + │ + Bob: ─────────X─── + + >>> print(cirq.quirk_url_to_circuit( + ... 'http://algassert.com/quirk#circuit={"cols":[["iswap"]]}', + ... extra_cell_makers={'iswap': cirq.ISWAP})) + 0: ───iSwap─── + │ + 1: ───iSwap─── + + >>> print(cirq.quirk_url_to_circuit( + ... 'http://algassert.com/quirk#circuit={"cols":[["iswap"]]}', + ... extra_cell_makers=[ + ... cirq.interop.quirk.cells.CellMaker( + ... identifier='iswap', + ... size=2, + ... maker=lambda args: cirq.ISWAP(*args.qubits)) + ... ])) + 0: ───iSwap─── + │ + 1: ───iSwap─── Returns: The parsed circuit. @@ -172,12 +173,13 @@ def quirk_json_to_circuit( a billion laughs attack in the form of nested custom gates. Examples: - >>> print(cirq.quirk_json_to_circuit( - ... {"cols":[["H"], ["•", "X"]]} - ... )) - 0: ───H───@─── - │ - 1: ───────X─── + + >>> print(cirq.quirk_json_to_circuit( + ... {"cols":[["H"], ["•", "X"]]} + ... )) + 0: ───H───@─── + │ + 1: ───────X─── Returns: The parsed circuit. diff --git a/cirq-core/cirq/protocols/apply_channel_protocol.py b/cirq-core/cirq/protocols/apply_channel_protocol.py index cd1a58b75d1..a6c8f283718 100644 --- a/cirq-core/cirq/protocols/apply_channel_protocol.py +++ b/cirq-core/cirq/protocols/apply_channel_protocol.py @@ -41,13 +41,16 @@ class ApplyChannelArgs: r"""Arguments for efficiently performing a channel. A channel performs the mapping - $$ - X \rightarrow \sum_i A_i X A_i^\dagger - $$ + + $$ + X \rightarrow \sum_i A_i X A_i^\dagger + $$ + for operators $A_i$ that satisfy the normalization condition - $$ - \sum_i A_i^\dagger A_i = I. - $$ + + $$ + \sum_i A_i^\dagger A_i = I. + $$ The receiving object is expected to mutate `target_tensor` so that it contains the density matrix after multiplication, and then return From d805d82375d221237d5dfe44d7c089c6911a0462 Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Tue, 19 Sep 2023 20:03:13 +0000 Subject: [PATCH 2/2] Make InternalGate hashable if all gate args are hashable (#6294) Review: @NoureldinYosri --- cirq-google/cirq_google/ops/internal_gate.py | 15 +++++++++-- .../cirq_google/ops/internal_gate_test.py | 26 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cirq-google/cirq_google/ops/internal_gate.py b/cirq-google/cirq_google/ops/internal_gate.py index 5822aa1fefa..f5e1f37d498 100644 --- a/cirq-google/cirq_google/ops/internal_gate.py +++ b/cirq-google/cirq_google/ops/internal_gate.py @@ -43,7 +43,7 @@ def __init__( self.gate_module = gate_module self.gate_name = gate_name self._num_qubits = num_qubits - self.gate_args = {arg: val for arg, val in kwargs.items()} + self.gate_args = kwargs def _num_qubits_(self) -> int: return self._num_qubits @@ -72,4 +72,15 @@ def _json_dict_(self) -> Dict[str, Any]: ) def _value_equality_values_(self): - return (self.gate_module, self.gate_name, self._num_qubits, self.gate_args) + hashable = True + for arg in self.gate_args.values(): + try: + hash(arg) + except TypeError: + hashable = False + return ( + self.gate_module, + self.gate_name, + self._num_qubits, + frozenset(self.gate_args.items()) if hashable else self.gate_args, + ) diff --git a/cirq-google/cirq_google/ops/internal_gate_test.py b/cirq-google/cirq_google/ops/internal_gate_test.py index 00fd480ccaa..b212d4f6151 100644 --- a/cirq-google/cirq_google/ops/internal_gate_test.py +++ b/cirq-google/cirq_google/ops/internal_gate_test.py @@ -14,6 +14,7 @@ import cirq import cirq_google +import pytest def test_internal_gate(): @@ -39,7 +40,30 @@ def test_internal_gate_with_no_args(): g = cirq_google.InternalGate(gate_name="GateWithNoArgs", gate_module='test', num_qubits=3) assert str(g) == 'test.GateWithNoArgs()' want_repr = ( - "cirq_google.InternalGate(gate_name='GateWithNoArgs', " "gate_module='test', num_qubits=3)" + "cirq_google.InternalGate(gate_name='GateWithNoArgs', gate_module='test', num_qubits=3)" ) assert repr(g) == want_repr assert cirq.qid_shape(g) == (2, 2, 2) + + +def test_internal_gate_with_hashable_args_is_hashable(): + hashable = cirq_google.InternalGate( + gate_name="GateWithHashableArgs", + gate_module='test', + num_qubits=3, + foo=1, + bar="2", + baz=(("a", 1),), + ) + _ = hash(hashable) + + unhashable = cirq_google.InternalGate( + gate_name="GateWithHashableArgs", + gate_module='test', + num_qubits=3, + foo=1, + bar="2", + baz={"a": 1}, + ) + with pytest.raises(TypeError, match="unhashable"): + _ = hash(unhashable)