From 9e2162215fea2acadca7125114958370ef12892a Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Sun, 17 Nov 2024 20:58:54 -0800 Subject: [PATCH 1/6] Have stale bot apply `status/stale` label for both issues and PRs (#6796) --- .github/workflows/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index dd7cb26365e..930b96efbd6 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,5 +14,6 @@ jobs: days-before-stale: 30 days-before-close: 30 close-issue-message: 'Issue closed due to inactivity.' - stale-issue-label: 'triage/stale' + stale-issue-label: 'status/stale' + stale-pr-label: 'status/stale' exempt-issue-labels: 'triage/accepted,triage/discuss,kind/design-issue,kind/health,kind/roadmap-item,kind/task' From b18063c8ba5cc62e9f2acc4ac5ce2b45236c7948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:35:52 +0000 Subject: [PATCH 2/6] Bump cross-spawn from 7.0.3 to 7.0.5 in /cirq-web/cirq_ts (#6798) --- cirq-web/cirq_ts/package-lock.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cirq-web/cirq_ts/package-lock.json b/cirq-web/cirq_ts/package-lock.json index 13a5905cab8..60688c57ab8 100644 --- a/cirq-web/cirq_ts/package-lock.json +++ b/cirq-web/cirq_ts/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@types/looks-same": "^4.1.0", "gts": "^3.1.1", - "live-server": "^1.2.1", + "live-server": "^1.2.2", "tsc-watch": "^4.2.9", "typescript": "^4.2.4" }, @@ -3487,10 +3487,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", From 326df25fe2257eb7492681f6e04b05eb7ffca617 Mon Sep 17 00:00:00 2001 From: Noureldin Date: Mon, 18 Nov 2024 13:54:44 -0800 Subject: [PATCH 3/6] Add custom args to value equality (#6799) --- cirq-google/cirq_google/ops/internal_gate.py | 1 + cirq-google/cirq_google/ops/internal_gate_test.py | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/cirq-google/cirq_google/ops/internal_gate.py b/cirq-google/cirq_google/ops/internal_gate.py index 021d5090045..5dadc8307db 100644 --- a/cirq-google/cirq_google/ops/internal_gate.py +++ b/cirq-google/cirq_google/ops/internal_gate.py @@ -100,6 +100,7 @@ def _value_equality_values_(self): self.gate_name, self._num_qubits, frozenset(self.gate_args.items()) if hashable else self.gate_args, + frozenset((k, v.SerializeToString()) for k, v in self.custom_args.items()), ) diff --git a/cirq-google/cirq_google/ops/internal_gate_test.py b/cirq-google/cirq_google/ops/internal_gate_test.py index 0768a70aeee..6473a23602a 100644 --- a/cirq-google/cirq_google/ops/internal_gate_test.py +++ b/cirq-google/cirq_google/ops/internal_gate_test.py @@ -134,3 +134,14 @@ def test_function_points_to_proto_invalid_args_raise(): with pytest.raises(ValueError, match='The dependent variable must be one dimensional'): _ = internal_gate.function_points_to_proto(x, np.zeros((10, 2))) + + +def test_custom_gates_are_taken_into_equality(): + msg1 = internal_gate.function_points_to_proto(x=np.linspace(0, 1, 10), y=np.random.random(10)) + msg2 = internal_gate.function_points_to_proto(x=np.linspace(-1, 0, 10), y=np.random.random(10)) + g1 = internal_gate.InternalGate('test', 'test', custom_args={'f1': msg1}) + g2 = internal_gate.InternalGate('test', 'test', custom_args={'f1': msg1}) + g3 = internal_gate.InternalGate('test', 'test', custom_args={'f1': msg2}) + + assert g1 == g2 + assert g1 != g3 From f2c7330a0d31a2d1d194ed5eaa15f0d5f75baca0 Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Mon, 18 Nov 2024 16:05:01 -0800 Subject: [PATCH 4/6] Preliminary support for outputting to OpenQASM 3.0 (#6795) * Preliminary support for outputting to OpenQASM 3.0 - This supports changing the version and the obvious changes in outputting to OpenQASM 3.0 - This PR does not cover imports from OpenQASM 3.0 --- cirq-core/cirq/circuits/circuit.py | 18 ++++++++--- cirq-core/cirq/circuits/circuit_test.py | 22 +++++++++++++- cirq-core/cirq/circuits/qasm_output.py | 30 +++++++++++++------ cirq-core/cirq/circuits/qasm_output_test.py | 2 +- .../ops/classically_controlled_operation.py | 2 +- cirq-core/cirq/ops/common_channels.py | 2 +- cirq-core/cirq/ops/common_gates.py | 18 +++++------ cirq-core/cirq/ops/identity.py | 2 +- cirq-core/cirq/ops/matrix_gates.py | 2 +- cirq-core/cirq/ops/measurement_gate.py | 7 +++-- cirq-core/cirq/ops/phased_x_gate.py | 2 +- cirq-core/cirq/ops/swap_gates.py | 2 +- cirq-core/cirq/ops/three_qubit_gates.py | 6 ++-- 13 files changed, 80 insertions(+), 35 deletions(-) diff --git a/cirq-core/cirq/circuits/circuit.py b/cirq-core/cirq/circuits/circuit.py index 3e0f10f8c6a..eaf5aff4a92 100644 --- a/cirq-core/cirq/circuits/circuit.py +++ b/cirq-core/cirq/circuits/circuit.py @@ -1318,14 +1318,19 @@ def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) return self return self._from_moments(resolved_moments) - def _qasm_(self) -> str: - return self.to_qasm() + def _qasm_(self, args: Optional['cirq.QasmArgs'] = None) -> str: + if args is None: + output = self._to_qasm_output() + else: + output = self._to_qasm_output(precision=args.precision, version=args.version) + return str(output) def _to_qasm_output( self, header: Optional[str] = None, precision: int = 10, qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + version: str = '2.0', ) -> 'cirq.QasmOutput': """Returns a QASM object equivalent to the circuit. @@ -1335,6 +1340,8 @@ def _to_qasm_output( precision: Number of digits to use when representing numbers. qubit_order: Determines how qubits are ordered in the QASM register. + version: Version of OpenQASM to render as output. Defaults + to OpenQASM 2.0. For OpenQASM 3.0, set this to '3.0'. """ if header is None: header = f'Generated from Cirq v{cirq._version.__version__}' @@ -1344,7 +1351,7 @@ def _to_qasm_output( qubits=qubits, header=header, precision=precision, - version='2.0', + version=version, ) def to_qasm( @@ -1352,6 +1359,7 @@ def to_qasm( header: Optional[str] = None, precision: int = 10, qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + version: str = '2.0', ) -> str: """Returns QASM equivalent to the circuit. @@ -1361,9 +1369,11 @@ def to_qasm( precision: Number of digits to use when representing numbers. qubit_order: Determines how qubits are ordered in the QASM register. + version: Version of OpenQASM to output. Defaults to OpenQASM 2.0. + Specify '3.0' if OpenQASM 3.0 is desired. """ - return str(self._to_qasm_output(header, precision, qubit_order)) + return str(self._to_qasm_output(header, precision, qubit_order, version)) def save_qasm( self, diff --git a/cirq-core/cirq/circuits/circuit_test.py b/cirq-core/cirq/circuits/circuit_test.py index a6e055ea2ee..f535b95bd61 100644 --- a/cirq-core/cirq/circuits/circuit_test.py +++ b/cirq-core/cirq/circuits/circuit_test.py @@ -3579,7 +3579,7 @@ def test_insert_operations_errors(): @pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit]) def test_to_qasm(circuit_cls): q0 = cirq.NamedQubit('q0') - circuit = circuit_cls(cirq.X(q0)) + circuit = circuit_cls(cirq.X(q0), cirq.measure(q0, key='mmm')) assert circuit.to_qasm() == cirq.qasm(circuit) assert ( circuit.to_qasm() @@ -3591,9 +3591,29 @@ def test_to_qasm(circuit_cls): // Qubits: [q0] qreg q[1]; +creg m_mmm[1]; + + +x q[0]; +measure q[0] -> m_mmm[0]; +""" + ) + assert circuit.to_qasm(version="3.0") == cirq.qasm(circuit, args=cirq.QasmArgs(version="3.0")) + assert ( + circuit.to_qasm(version="3.0") + == f"""// Generated from Cirq v{cirq.__version__} + +OPENQASM 3.0; +include "stdgates.inc"; + + +// Qubits: [q0] +qubit[1] q; +bit[1] m_mmm; x q[0]; +m_mmm[0] = measure q[0]; """ ) diff --git a/cirq-core/cirq/circuits/qasm_output.py b/cirq-core/cirq/circuits/qasm_output.py index 2ae5ae20b61..947d21dbf55 100644 --- a/cirq-core/cirq/circuits/qasm_output.py +++ b/cirq-core/cirq/circuits/qasm_output.py @@ -54,7 +54,7 @@ def _has_unitary_(self): return True def _qasm_(self, qubits: Tuple['cirq.Qid', ...], args: 'cirq.QasmArgs') -> str: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format( 'u3({0:half_turns},{1:half_turns},{2:half_turns}) {3};\n', self.theta, @@ -246,7 +246,7 @@ def __str__(self) -> str: return ''.join(output) def _write_qasm(self, output_func: Callable[[str], None]) -> None: - self.args.validate_version('2.0') + self.args.validate_version('2.0', '3.0') # Generate nice line spacing line_gap = [0] @@ -267,8 +267,12 @@ def output(text): output('\n') # Version - output('OPENQASM 2.0;\n') - output('include "qelib1.inc";\n') + output(f'OPENQASM {self.args.version};\n') + if self.args.version == '2.0': + output('include "qelib1.inc";\n') + else: + output('include "stdgates.inc";\n') + output_line_gap(2) # Function definitions @@ -276,9 +280,13 @@ def output(text): # Register definitions # Qubit registers + output(f"// Qubits: [{', '.join(map(str, self.qubits))}]\n") if len(self.qubits) > 0: - output(f'qreg q[{len(self.qubits)}];\n') + if self.args.version == '2.0': + output(f'qreg q[{len(self.qubits)}];\n') + else: + output(f'qubit[{len(self.qubits)}] q;\n') # Classical registers # Pick an id for the creg that will store each measurement already_output_keys: Set[str] = set() @@ -288,11 +296,15 @@ def output(text): continue already_output_keys.add(key) meas_id = self.args.meas_key_id_map[key] - comment = self.meas_comments[key] - if comment is None: - output(f'creg {meas_id}[{len(meas.qubits)}];\n') + if self.meas_comments[key] is not None: + comment = f' // Measurement: {self.meas_comments[key]}' + else: + comment = '' + + if self.args.version == '2.0': + output(f'creg {meas_id}[{len(meas.qubits)}];{comment}\n') else: - output(f'creg {meas_id}[{len(meas.qubits)}]; // Measurement: {comment}\n') + output(f'bit[{len(meas.qubits)}] {meas_id};{comment}\n') # In OpenQASM 2.0, the transformation of global phase gates is ignored. # Therefore, no newline is created when the operations contained in # a circuit consist only of global phase gates. diff --git a/cirq-core/cirq/circuits/qasm_output_test.py b/cirq-core/cirq/circuits/qasm_output_test.py index ad4e0d44528..14abacc9b63 100644 --- a/cirq-core/cirq/circuits/qasm_output_test.py +++ b/cirq-core/cirq/circuits/qasm_output_test.py @@ -225,7 +225,7 @@ def test_precision(): def test_version(): (q0,) = _make_qubits(1) with pytest.raises(ValueError): - output = cirq.QasmOutput((), (q0,), version='3.0') + output = cirq.QasmOutput((), (q0,), version='4.0') _ = str(output) diff --git a/cirq-core/cirq/ops/classically_controlled_operation.py b/cirq-core/cirq/ops/classically_controlled_operation.py index d4c53bdb367..3a323e53b51 100644 --- a/cirq-core/cirq/ops/classically_controlled_operation.py +++ b/cirq-core/cirq/ops/classically_controlled_operation.py @@ -216,7 +216,7 @@ def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']: return local_keys.union(protocols.control_keys(self._sub_operation)) def _qasm_(self, args: 'cirq.QasmArgs') -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if len(self._conditions) > 1: raise ValueError('QASM does not support multiple conditions.') subop_qasm = protocols.qasm(self._sub_operation, args=args) diff --git a/cirq-core/cirq/ops/common_channels.py b/cirq-core/cirq/ops/common_channels.py index b619aceb9f7..183973218e0 100644 --- a/cirq-core/cirq/ops/common_channels.py +++ b/cirq-core/cirq/ops/common_channels.py @@ -702,7 +702,7 @@ def _has_stabilizer_effect_(self) -> Optional[bool]: return True def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('reset {0};\n', qubits[0]) def _qid_shape_(self): diff --git a/cirq-core/cirq/ops/common_gates.py b/cirq-core/cirq/ops/common_gates.py index fea2ac9996f..4d2a12cc94f 100644 --- a/cirq-core/cirq/ops/common_gates.py +++ b/cirq-core/cirq/ops/common_gates.py @@ -272,7 +272,7 @@ def _circuit_diagram_info_( ) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if self._global_shift == 0: if self._exponent == 1: return args.format('x {0};\n', qubits[0]) @@ -374,7 +374,7 @@ def __repr__(self) -> str: return f'cirq.Rx(rads={proper_repr(self._rads)})' def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0]) def _json_dict_(self) -> Dict[str, Any]: @@ -478,7 +478,7 @@ def _circuit_diagram_info_( ) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if self._exponent == 1 and self.global_shift != -0.5: return args.format('y {0};\n', qubits[0]) @@ -560,7 +560,7 @@ def __repr__(self) -> str: return f'cirq.Ry(rads={proper_repr(self._rads)})' def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('ry({0:half_turns}) {1};\n', self._exponent, qubits[0]) def _json_dict_(self) -> Dict[str, Any]: @@ -791,7 +791,7 @@ def _circuit_diagram_info_( return protocols.CircuitDiagramInfo(wire_symbols=('Z',), exponent=e) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if self.global_shift == 0: if self._exponent == 1: @@ -910,7 +910,7 @@ def __repr__(self) -> str: return f'cirq.Rz(rads={proper_repr(self._rads)})' def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0]) def _json_dict_(self) -> Dict[str, Any]: @@ -1016,7 +1016,7 @@ def _circuit_diagram_info_( ) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if self._exponent == 0: return args.format('id {0};\n', qubits[0]) elif self._exponent == 1 and self._global_shift == 0: @@ -1204,7 +1204,7 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('cz {0},{1};\n', qubits[0], qubits[1]) def _has_stabilizer_effect_(self) -> Optional[bool]: @@ -1405,7 +1405,7 @@ def controlled( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('cx {0},{1};\n', qubits[0], qubits[1]) def _has_stabilizer_effect_(self) -> Optional[bool]: diff --git a/cirq-core/cirq/ops/identity.py b/cirq-core/cirq/ops/identity.py index 46de3bea8fd..37035b0cea2 100644 --- a/cirq-core/cirq/ops/identity.py +++ b/cirq-core/cirq/ops/identity.py @@ -138,7 +138,7 @@ def _circuit_diagram_info_(self, args) -> Tuple[str, ...]: return ('I',) * self.num_qubits() def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return ''.join([args.format('id {0};\n', qubit) for qubit in qubits]) @classmethod diff --git a/cirq-core/cirq/ops/matrix_gates.py b/cirq-core/cirq/ops/matrix_gates.py index bb2315bc38e..6d5ee10fc7f 100644 --- a/cirq-core/cirq/ops/matrix_gates.py +++ b/cirq-core/cirq/ops/matrix_gates.py @@ -181,7 +181,7 @@ def _circuit_diagram_info_( return protocols.CircuitDiagramInfo(wire_symbols=[main, *rest]) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') if self._qid_shape == (2,): return protocols.qasm( phased_x_z_gate.PhasedXZGate.from_matrix(self._matrix), args=args, qubits=qubits diff --git a/cirq-core/cirq/ops/measurement_gate.py b/cirq-core/cirq/ops/measurement_gate.py index 6fa235a6cc8..8a589332988 100644 --- a/cirq-core/cirq/ops/measurement_gate.py +++ b/cirq-core/cirq/ops/measurement_gate.py @@ -227,7 +227,7 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: if self.confusion_map or not all(d == 2 for d in self._qid_shape): return NotImplemented - args.validate_version('2.0') + args.validate_version('2.0', '3.0') invert_mask = self.invert_mask if len(invert_mask) < len(qubits): invert_mask = invert_mask + (False,) * (len(qubits) - len(invert_mask)) @@ -235,7 +235,10 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio for i, (qubit, inv) in enumerate(zip(qubits, invert_mask)): if inv: lines.append(args.format('x {0}; // Invert the following measurement\n', qubit)) - lines.append(args.format('measure {0} -> {1:meas}[{2}];\n', qubit, self.key, i)) + if args.version == '2.0': + lines.append(args.format('measure {0} -> {1:meas}[{2}];\n', qubit, self.key, i)) + else: + lines.append(args.format('{1:meas}[{2}] = measure {0};\n', qubit, self.key, i)) if inv: lines.append(args.format('x {0}; // Undo the inversion\n', qubit)) return ''.join(lines) diff --git a/cirq-core/cirq/ops/phased_x_gate.py b/cirq-core/cirq/ops/phased_x_gate.py index 4a1b6069268..510d5f85b8d 100644 --- a/cirq-core/cirq/ops/phased_x_gate.py +++ b/cirq-core/cirq/ops/phased_x_gate.py @@ -69,7 +69,7 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio if cirq.is_parameterized(self): return None - args.validate_version('2.0') + args.validate_version('2.0', '3.0') e = cast(float, value.canonicalize_half_turns(self._exponent)) p = cast(float, self.phase_exponent) diff --git a/cirq-core/cirq/ops/swap_gates.py b/cirq-core/cirq/ops/swap_gates.py index 11092d73954..aea900373f0 100644 --- a/cirq-core/cirq/ops/swap_gates.py +++ b/cirq-core/cirq/ops/swap_gates.py @@ -148,7 +148,7 @@ def _circuit_diagram_info_( def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: if self._exponent != 1: return None # Don't have an equivalent gate in QASM - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('swap {0},{1};\n', qubits[0], qubits[1]) def __str__(self) -> str: diff --git a/cirq-core/cirq/ops/three_qubit_gates.py b/cirq-core/cirq/ops/three_qubit_gates.py index a4f8250dba5..8550eb66e13 100644 --- a/cirq-core/cirq/ops/three_qubit_gates.py +++ b/cirq-core/cirq/ops/three_qubit_gates.py @@ -164,7 +164,7 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio if self._exponent != 1: return None - args.validate_version('2.0') + args.validate_version('2.0', '3.0') lines = [ args.format('h {0};\n', qubits[2]), args.format('ccx {0},{1},{2};\n', qubits[0], qubits[1], qubits[2]), @@ -483,7 +483,7 @@ def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optio if self._exponent != 1: return None - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('ccx {0},{1},{2};\n', qubits[0], qubits[1], qubits[2]) def __repr__(self) -> str: @@ -661,7 +661,7 @@ def _circuit_diagram_info_( return protocols.CircuitDiagramInfo(('@', '×', '×')) def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: - args.validate_version('2.0') + args.validate_version('2.0', '3.0') return args.format('cswap {0},{1},{2};\n', qubits[0], qubits[1], qubits[2]) def _value_equality_values_(self): From b35382fef518718608a5ca152a576e0fb705186a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 21:47:51 -0800 Subject: [PATCH 5/6] Bump cross-spawn from 7.0.3 to 7.0.5 in /cirq-web/cirq_ts (#6801) Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.5. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cirq-web/cirq_ts/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cirq-web/cirq_ts/package-lock.json b/cirq-web/cirq_ts/package-lock.json index 60688c57ab8..5742270efe7 100644 --- a/cirq-web/cirq_ts/package-lock.json +++ b/cirq-web/cirq_ts/package-lock.json @@ -3487,9 +3487,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", From 7096acdf8e6cb525f60393df628928421ec5c034 Mon Sep 17 00:00:00 2001 From: Divyanshu Verma <63949148+dv8081@users.noreply.github.com> Date: Wed, 20 Nov 2024 01:35:01 +0530 Subject: [PATCH 6/6] Fix Moment.resolve_parameter for constant sympy expressions (#6794) Problem: `Moment._resolve_parameters_` might keep constant sympy expression if its resolved value is numerically equal. Solution: Check if parameterization changed for the resolved operation and if so replace the original operation with resolved (even if equal). Fixes #6778 --------- Co-authored-by: Pavol Juhas Co-authored-by: Noureldin --- cirq-core/cirq/circuits/moment.py | 7 +++++-- cirq-core/cirq/circuits/moment_test.py | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/circuits/moment.py b/cirq-core/cirq/circuits/moment.py index b64957eeb1e..4a6be179e70 100644 --- a/cirq-core/cirq/circuits/moment.py +++ b/cirq-core/cirq/circuits/moment.py @@ -275,8 +275,11 @@ def _resolve_parameters_( resolved_ops: List['cirq.Operation'] = [] for op in self: resolved_op = protocols.resolve_parameters(op, resolver, recursive) - if resolved_op != op: - changed = True + changed = ( + changed + or resolved_op != op + or (protocols.is_parameterized(op) and not protocols.is_parameterized(resolved_op)) + ) resolved_ops.append(resolved_op) if not changed: return self diff --git a/cirq-core/cirq/circuits/moment_test.py b/cirq-core/cirq/circuits/moment_test.py index b31457223d9..bbe738d3879 100644 --- a/cirq-core/cirq/circuits/moment_test.py +++ b/cirq-core/cirq/circuits/moment_test.py @@ -294,6 +294,14 @@ def test_resolve_parameters(): moment = cirq.Moment(cirq.X(a) ** sympy.Symbol('v'), cirq.Y(b) ** sympy.Symbol('w')) resolved_moment = cirq.resolve_parameters(moment, cirq.ParamResolver({'v': 0.1, 'w': 0.2})) assert resolved_moment == cirq.Moment(cirq.X(a) ** 0.1, cirq.Y(b) ** 0.2) + # sympy constant is resolved to a Python number + moment = cirq.Moment(cirq.Rz(rads=sympy.pi).on(a)) + resolved_moment = cirq.resolve_parameters(moment, {'pi': np.pi}) + assert resolved_moment == cirq.Moment(cirq.Rz(rads=np.pi).on(a)) + resolved_gate = resolved_moment.operations[0].gate + assert not isinstance(resolved_gate.exponent, sympy.Basic) + assert isinstance(resolved_gate.exponent, float) + assert not cirq.is_parameterized(resolved_moment) def test_resolve_parameters_no_change():