Skip to content

Commit 40a8e3a

Browse files
committed
Add utility methods for efficiently constructing circuits and moments
1 parent 2a57894 commit 40a8e3a

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

cirq-core/cirq/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@
6666
from cirq.circuits import (
6767
AbstractCircuit,
6868
Alignment,
69+
c,
6970
Circuit,
7071
CircuitOperation,
7172
FrozenCircuit,
7273
InsertStrategy,
74+
m,
7375
Moment,
7476
PointOptimizationSummary,
7577
PointOptimizer,

cirq-core/cirq/circuits/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from cirq.circuits.circuit import AbstractCircuit, Alignment, Circuit
2222
from cirq.circuits.circuit_operation import CircuitOperation
23+
from cirq.circuits.circuit_util import c, m
2324
from cirq.circuits.frozen_circuit import FrozenCircuit
2425
from cirq.circuits.insert_strategy import InsertStrategy
2526

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright 2023 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import TYPE_CHECKING
16+
17+
from cirq.circuits.frozen_circuit import FrozenCircuit
18+
from cirq.circuits.moment import Moment
19+
20+
if TYPE_CHECKING:
21+
import cirq
22+
23+
24+
def m(*ops: 'cirq.Operation') -> 'cirq.Moment':
25+
"""Constructs a Moment from Operations.
26+
27+
This is shorthand for calling Moment.from_ops.
28+
29+
Args:
30+
*ops: Operations to be included in the new moment.
31+
"""
32+
return Moment.from_ops(*ops)
33+
34+
35+
def c(*moments: 'cirq.Moment') -> 'cirq.FrozenCircuit':
36+
"""Constructs a FrozenCircuit from Moments.
37+
38+
This is shorthand for calling FrozenCircuit.from_moments.
39+
40+
Args:
41+
*moments: Moments to be included in the new circuit.
42+
"""
43+
return FrozenCircuit.from_moments(*moments)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2023 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import cirq
16+
17+
18+
def test_cirq_m():
19+
moment = cirq.m(cirq.X(cirq.q(0)), cirq.Y(cirq.q(1)))
20+
assert isinstance(moment, cirq.Moment)
21+
22+
23+
def test_cirq_c():
24+
qubits = cirq.LineQubit.range(10)
25+
circuit = cirq.c(cirq.m(*cirq.H.on_each(*qubits)), cirq.m(cirq.measure(*qubits)))
26+
assert isinstance(circuit, cirq.FrozenCircuit)

cirq-core/cirq/circuits/moment.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
AbstractSet,
2020
Any,
2121
Callable,
22+
cast,
2223
Dict,
2324
FrozenSet,
2425
Iterable,
@@ -80,17 +81,26 @@ class Moment:
8081
are no such operations, returns an empty Moment.
8182
"""
8283

83-
def __init__(self, *contents: 'cirq.OP_TREE') -> None:
84+
def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) -> None:
8485
"""Constructs a moment with the given operations.
8586
8687
Args:
8788
contents: The operations applied within the moment.
8889
Will be flattened and frozen into a tuple before storing.
90+
_flatten_contents: If True, use flatten_to_ops to convert
91+
the OP_TREE of contents into a tuple of Operation. If False,
92+
we skip flattening and assume that contents already consists
93+
of individual operations. This is used internally by helper
94+
methods to avoid unnecessary validation.
8995
9096
Raises:
9197
ValueError: A qubit appears more than once.
9298
"""
93-
self._operations = tuple(op_tree.flatten_to_ops(contents))
99+
self._operations = (
100+
tuple(op_tree.flatten_to_ops(contents))
101+
if _flatten_contents
102+
else cast(Tuple['cirq.Operation'], contents)
103+
)
94104
self._sorted_operations: Optional[Tuple['cirq.Operation', ...]] = None
95105

96106
# An internal dictionary to support efficient operation access by qubit.
@@ -106,6 +116,10 @@ def __init__(self, *contents: 'cirq.OP_TREE') -> None:
106116
self._measurement_key_objs: Optional[FrozenSet['cirq.MeasurementKey']] = None
107117
self._control_keys: Optional[FrozenSet['cirq.MeasurementKey']] = None
108118

119+
@classmethod
120+
def from_ops(cls, *ops: 'cirq.Operation') -> 'cirq.Moment':
121+
return cls(*ops, _flatten_contents=False)
122+
109123
@property
110124
def operations(self) -> Tuple['cirq.Operation', ...]:
111125
return self._operations

0 commit comments

Comments
 (0)