cirq-core 1.5.0.dev20250311162344__py3-none-any.whl → 1.5.0.dev20250311225949__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cirq-core might be problematic. Click here for more details.

cirq/_version.py CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 10, 0): # pragma: no cover
28
28
  'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
29
  )
30
30
 
31
- __version__ = "1.5.0.dev20250311162344"
31
+ __version__ = "1.5.0.dev20250311225949"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.5.0.dev20250311162344"
6
+ assert cirq.__version__ == "1.5.0.dev20250311225949"
cirq/circuits/circuit.py CHANGED
@@ -69,6 +69,7 @@ if TYPE_CHECKING:
69
69
 
70
70
 
71
71
  _TGate = TypeVar('_TGate', bound='cirq.Gate')
72
+ _MOMENT_OR_OP = Union['cirq.Moment', 'cirq.Operation']
72
73
 
73
74
  CIRCUIT_TYPE = TypeVar('CIRCUIT_TYPE', bound='AbstractCircuit')
74
75
  document(
@@ -2095,49 +2096,6 @@ class Circuit(AbstractCircuit):
2095
2096
  last_available = k
2096
2097
  return last_available
2097
2098
 
2098
- def _pick_or_create_inserted_op_moment_index(
2099
- self, splitter_index: int, op: 'cirq.Operation', strategy: 'cirq.InsertStrategy'
2100
- ) -> int:
2101
- """Determines and prepares where an insertion will occur.
2102
-
2103
- Args:
2104
- splitter_index: The index to insert at.
2105
- op: The operation that will be inserted.
2106
- strategy: The insertion strategy.
2107
-
2108
- Returns:
2109
- The index of the (possibly new) moment where the insertion should
2110
- occur.
2111
-
2112
- Raises:
2113
- ValueError: Unrecognized append strategy.
2114
- """
2115
-
2116
- if strategy is InsertStrategy.NEW or strategy is InsertStrategy.NEW_THEN_INLINE:
2117
- self._moments.insert(splitter_index, Moment())
2118
- self._mutated()
2119
- return splitter_index
2120
-
2121
- if strategy is InsertStrategy.INLINE:
2122
- if 0 <= splitter_index - 1 < len(self._moments) and self._can_add_op_at(
2123
- splitter_index - 1, op
2124
- ):
2125
- return splitter_index - 1
2126
-
2127
- return self._pick_or_create_inserted_op_moment_index(
2128
- splitter_index, op, InsertStrategy.NEW
2129
- )
2130
-
2131
- if strategy is InsertStrategy.EARLIEST:
2132
- if self._can_add_op_at(splitter_index, op):
2133
- return self.earliest_available_moment(op, end_moment_index=splitter_index)
2134
-
2135
- return self._pick_or_create_inserted_op_moment_index(
2136
- splitter_index, op, InsertStrategy.INLINE
2137
- )
2138
-
2139
- raise ValueError(f'Unrecognized append strategy: {strategy}')
2140
-
2141
2099
  def _can_add_op_at(self, moment_index: int, operation: 'cirq.Operation') -> bool:
2142
2100
  if not 0 <= moment_index < len(self._moments):
2143
2101
  return True
@@ -2147,7 +2105,7 @@ class Circuit(AbstractCircuit):
2147
2105
  def insert(
2148
2106
  self,
2149
2107
  index: int,
2150
- moment_or_operation_tree: Union['cirq.Operation', 'cirq.OP_TREE'],
2108
+ moment_or_operation_tree: 'cirq.OP_TREE',
2151
2109
  strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST,
2152
2110
  ) -> int:
2153
2111
  """Inserts operations into the circuit.
@@ -2170,24 +2128,57 @@ class Circuit(AbstractCircuit):
2170
2128
  """
2171
2129
  # limit index to 0..len(self._moments), also deal with indices smaller 0
2172
2130
  k = max(min(index if index >= 0 else len(self._moments) + index, len(self._moments)), 0)
2173
- if strategy != InsertStrategy.EARLIEST or index != len(self._moments):
2131
+ if strategy != InsertStrategy.EARLIEST or k != len(self._moments):
2174
2132
  self._placement_cache = None
2175
- for moment_or_op in list(ops.flatten_to_ops_or_moments(moment_or_operation_tree)):
2176
- if self._placement_cache:
2177
- p = self._placement_cache.append(moment_or_op)
2178
- elif isinstance(moment_or_op, Moment):
2179
- p = k
2180
- else:
2181
- p = self._pick_or_create_inserted_op_moment_index(k, moment_or_op, strategy)
2182
- if isinstance(moment_or_op, Moment):
2183
- self._moments.insert(p, moment_or_op)
2184
- elif p == len(self._moments):
2185
- self._moments.append(Moment(moment_or_op))
2186
- else:
2187
- self._moments[p] = self._moments[p].with_operation(moment_or_op)
2188
- k = max(k, p + 1)
2189
- if strategy is InsertStrategy.NEW_THEN_INLINE:
2190
- strategy = InsertStrategy.INLINE
2133
+ mops = list(ops.flatten_to_ops_or_moments(moment_or_operation_tree))
2134
+ if self._placement_cache:
2135
+ batches = [mops] # Any grouping would work here; this just happens to be the fastest.
2136
+ elif strategy is InsertStrategy.NEW:
2137
+ batches = [[mop] for mop in mops] # Each op goes into its own moment.
2138
+ else:
2139
+ batches = list(_group_into_moment_compatible(mops))
2140
+ for batch in batches:
2141
+ # Insert a moment if inline/earliest and _any_ op in the batch requires it.
2142
+ if (
2143
+ not self._placement_cache
2144
+ and not isinstance(batch[0], Moment)
2145
+ and strategy in (InsertStrategy.INLINE, InsertStrategy.EARLIEST)
2146
+ and not all(
2147
+ (strategy is InsertStrategy.EARLIEST and self._can_add_op_at(k, op))
2148
+ or (k > 0 and self._can_add_op_at(k - 1, op))
2149
+ for op in cast(List['cirq.Operation'], batch)
2150
+ )
2151
+ ):
2152
+ self._moments.insert(k, Moment())
2153
+ if strategy is InsertStrategy.INLINE:
2154
+ k += 1
2155
+ max_p = 0
2156
+ for moment_or_op in batch:
2157
+ # Determine Placement
2158
+ if self._placement_cache:
2159
+ p = self._placement_cache.append(moment_or_op)
2160
+ elif isinstance(moment_or_op, Moment):
2161
+ p = k
2162
+ elif strategy in (InsertStrategy.NEW, InsertStrategy.NEW_THEN_INLINE):
2163
+ self._moments.insert(k, Moment())
2164
+ p = k
2165
+ elif strategy is InsertStrategy.INLINE:
2166
+ p = k - 1
2167
+ else: # InsertStrategy.EARLIEST:
2168
+ p = self.earliest_available_moment(moment_or_op, end_moment_index=k)
2169
+ # Place
2170
+ if isinstance(moment_or_op, Moment):
2171
+ self._moments.insert(p, moment_or_op)
2172
+ elif p == len(self._moments):
2173
+ self._moments.append(Moment(moment_or_op))
2174
+ else:
2175
+ self._moments[p] = self._moments[p].with_operation(moment_or_op)
2176
+ # Iterate
2177
+ max_p = max(p, max_p)
2178
+ if strategy is InsertStrategy.NEW_THEN_INLINE:
2179
+ strategy = InsertStrategy.INLINE
2180
+ k += 1
2181
+ k = max(k, max_p + 1)
2191
2182
  self._mutated(preserve_placement_cache=True)
2192
2183
  return k
2193
2184
 
@@ -2450,7 +2441,7 @@ class Circuit(AbstractCircuit):
2450
2441
 
2451
2442
  def append(
2452
2443
  self,
2453
- moment_or_operation_tree: Union['cirq.Moment', 'cirq.OP_TREE'],
2444
+ moment_or_operation_tree: 'cirq.OP_TREE',
2454
2445
  strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST,
2455
2446
  ) -> None:
2456
2447
  """Appends operations onto the end of the circuit.
@@ -2841,8 +2832,40 @@ def _group_until_different(items: Iterable[_TIn], key: Callable[[_TIn], _TKey],
2841
2832
  return ((k, [val(i) for i in v]) for (k, v) in itertools.groupby(items, key))
2842
2833
 
2843
2834
 
2835
+ def _group_into_moment_compatible(inputs: Sequence[_MOMENT_OR_OP]) -> Iterator[List[_MOMENT_OR_OP]]:
2836
+ """Groups sequential ops into those that can coexist in a single moment.
2837
+
2838
+ This function will go through the input sequence in order, emitting lists of sequential
2839
+ operations that can go into a single moment. It does not try to rearrange the elements or try
2840
+ to move them to open slots in earlier moments; it simply processes them in order and outputs
2841
+ them. i.e. the output, if flattened, will equal the input.
2842
+
2843
+ Actual Moments in the input will always be emitted by themselves as a single-element list.
2844
+
2845
+ Examples:
2846
+ [X(a), X(b), X(a)] -> [[X(a), X(b)], [X(a)]]
2847
+ [X(a), X(a), X(b)] -> [[X(a)], [X(a), X(b)]]
2848
+ [X(a), Moment(X(b)), X(c)] -> [[X(a)], [Moment(X(b))], [X(c)]]
2849
+ """
2850
+ batch: List[_MOMENT_OR_OP] = []
2851
+ batch_qubits: Set['cirq.Qid'] = set()
2852
+ for mop in inputs:
2853
+ is_moment = isinstance(mop, cirq.Moment)
2854
+ if (is_moment and batch) or not batch_qubits.isdisjoint(mop.qubits):
2855
+ yield batch
2856
+ batch = []
2857
+ batch_qubits.clear()
2858
+ if is_moment:
2859
+ yield [mop]
2860
+ continue
2861
+ batch.append(mop)
2862
+ batch_qubits.update(mop.qubits)
2863
+ if batch:
2864
+ yield batch
2865
+
2866
+
2844
2867
  def get_earliest_accommodating_moment_index(
2845
- moment_or_operation: Union['cirq.Moment', 'cirq.Operation'],
2868
+ moment_or_operation: _MOMENT_OR_OP,
2846
2869
  qubit_indices: Dict['cirq.Qid', int],
2847
2870
  mkey_indices: Dict['cirq.MeasurementKey', int],
2848
2871
  ckey_indices: Dict['cirq.MeasurementKey', int],
@@ -2938,7 +2961,7 @@ class _PlacementCache:
2938
2961
  # For keeping track of length of the circuit thus far.
2939
2962
  self._length = 0
2940
2963
 
2941
- def append(self, moment_or_operation: Union['cirq.Moment', 'cirq.Operation']) -> int:
2964
+ def append(self, moment_or_operation: _MOMENT_OR_OP) -> int:
2942
2965
  """Find placement for moment/operation and update cache.
2943
2966
 
2944
2967
  Determines the placement index of the provided operation, assuming
@@ -3555,6 +3555,52 @@ def test_insert_operations_random_circuits(circuit):
3555
3555
  assert circuit == other_circuit
3556
3556
 
3557
3557
 
3558
+ def test_insert_zero_index():
3559
+ # Should always go to moment[0], independent of qubit order or earliest/inline strategy.
3560
+ q0, q1 = cirq.LineQubit.range(2)
3561
+ c0 = cirq.Circuit(cirq.X(q0))
3562
+ c0.insert(0, cirq.Y.on_each(q0, q1), strategy=cirq.InsertStrategy.EARLIEST)
3563
+ c1 = cirq.Circuit(cirq.X(q0))
3564
+ c1.insert(0, cirq.Y.on_each(q1, q0), strategy=cirq.InsertStrategy.EARLIEST)
3565
+ c2 = cirq.Circuit(cirq.X(q0))
3566
+ c2.insert(0, cirq.Y.on_each(q0, q1), strategy=cirq.InsertStrategy.INLINE)
3567
+ c3 = cirq.Circuit(cirq.X(q0))
3568
+ c3.insert(0, cirq.Y.on_each(q1, q0), strategy=cirq.InsertStrategy.INLINE)
3569
+ expected = cirq.Circuit(cirq.Moment(cirq.Y(q0), cirq.Y(q1)), cirq.Moment(cirq.X(q0)))
3570
+ assert c0 == expected
3571
+ assert c1 == expected
3572
+ assert c2 == expected
3573
+ assert c3 == expected
3574
+
3575
+
3576
+ def test_insert_earliest_on_previous_moment():
3577
+ q = cirq.LineQubit(0)
3578
+ c = cirq.Circuit(cirq.Moment(cirq.X(q)), cirq.Moment(), cirq.Moment(), cirq.Moment(cirq.Z(q)))
3579
+ c.insert(3, cirq.Y(q), strategy=cirq.InsertStrategy.EARLIEST)
3580
+ # Should fall back to moment[1] since EARLIEST
3581
+ assert c == cirq.Circuit(
3582
+ cirq.Moment(cirq.X(q)), cirq.Moment(cirq.Y(q)), cirq.Moment(), cirq.Moment(cirq.Z(q))
3583
+ )
3584
+
3585
+
3586
+ def test_insert_inline_end_of_circuit():
3587
+ # If end index is specified, INLINE should place all ops there independent of qubit order.
3588
+ q0, q1 = cirq.LineQubit.range(2)
3589
+ c0 = cirq.Circuit(cirq.X(q0))
3590
+ c0.insert(1, cirq.Y.on_each(q0, q1), strategy=cirq.InsertStrategy.INLINE)
3591
+ c1 = cirq.Circuit(cirq.X(q0))
3592
+ c1.insert(1, cirq.Y.on_each(q1, q0), strategy=cirq.InsertStrategy.INLINE)
3593
+ c2 = cirq.Circuit(cirq.X(q0))
3594
+ c2.insert(5, cirq.Y.on_each(q0, q1), strategy=cirq.InsertStrategy.INLINE)
3595
+ c3 = cirq.Circuit(cirq.X(q0))
3596
+ c3.insert(5, cirq.Y.on_each(q1, q0), strategy=cirq.InsertStrategy.INLINE)
3597
+ expected = cirq.Circuit(cirq.Moment(cirq.X(q0)), cirq.Moment(cirq.Y(q0), cirq.Y(q1)))
3598
+ assert c0 == expected
3599
+ assert c1 == expected
3600
+ assert c2 == expected
3601
+ assert c3 == expected
3602
+
3603
+
3558
3604
  def test_insert_operations_errors():
3559
3605
  a, b, c = (cirq.NamedQubit(s) for s in 'abc')
3560
3606
  with pytest.raises(ValueError):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cirq-core
3
- Version: 1.5.0.dev20250311162344
3
+ Version: 1.5.0.dev20250311225949
4
4
  Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
5
5
  Home-page: http://github.com/quantumlib/cirq
6
6
  Author: The Cirq Developers
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=Qq3ZcfgD-Nb81cEppQdJqhAyrVqXKtfXZYGXT0p-Wh0,34718
4
4
  cirq/_doc.py,sha256=yDyWUD_2JDS0gShfGRb-rdqRt9-WeL7DhkqX7np0Nko,2879
5
5
  cirq/_import.py,sha256=p9gMHJscbtDDkfHOaulvd3Aer0pwUF5AXpL89XR8dNw,8402
6
6
  cirq/_import_test.py,sha256=6K_v0riZJXOXUphHNkGA8MY-JcmGlezFaGmvrNhm3OQ,1015
7
- cirq/_version.py,sha256=0jQNqyAXPPR2m_0Cceo30B_Npdi1orWlYtRNa5Ytrng,1206
8
- cirq/_version_test.py,sha256=nfSM4ulXoZ6SAfAtYOQo-Wv8-og3LOUeXq9tS2-iH6Y,147
7
+ cirq/_version.py,sha256=x7NRTtA6TLyIZIExmItmYlBevUVZMham8AkyCnIMCC8,1206
8
+ cirq/_version_test.py,sha256=_BAiB6lA6liUbnJpI04Qo5SlkBtO9nRLIDI1xkM0iv4,147
9
9
  cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
10
10
  cirq/json_resolver_cache.py,sha256=p-vEOa-8GQ2cFIAdze-kd6C1un1uRvtujVPljVKaHBg,13557
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -16,10 +16,10 @@ cirq/circuits/_box_drawing_character_data.py,sha256=QLoCXwcLL7091RdxEKO259goxt4R
16
16
  cirq/circuits/_box_drawing_character_data_test.py,sha256=XO94z0piwZRHaNZHTf-5tKHQ4MKcDruMeRIKdT8GbYA,1624
17
17
  cirq/circuits/_bucket_priority_queue.py,sha256=hxFuii2fKD8G6EKT_aVLEsA7FmSfqFXPwIbA0KsoSC4,6745
18
18
  cirq/circuits/_bucket_priority_queue_test.py,sha256=t6u_hG7K2e2WKWrgCsKxNRtp4ghKwiCrp0_WSY0W25k,5288
19
- cirq/circuits/circuit.py,sha256=tnjeicaaYZdgC4nfNnXTOA2MXrOTuEwtUDkHAuCH2Pw,118161
19
+ cirq/circuits/circuit.py,sha256=xpRLGDg2jpMpJC4GHJe3drP2s9y1OdXnsPxGPf1YQlM,119444
20
20
  cirq/circuits/circuit_operation.py,sha256=ebI2KBvQLcBYgjQXKO6y6jB2EDLgwtxdZBRs3hSYaLM,36438
21
21
  cirq/circuits/circuit_operation_test.py,sha256=SFyM12Ky7-OVwl-jK3OTMMN0DD5hR6tWfx_v7m6HUMo,48866
22
- cirq/circuits/circuit_test.py,sha256=BZjwavIekWR2hgG1yV0Acgt7-Q05cOjugozrLgYdx7k,161268
22
+ cirq/circuits/circuit_test.py,sha256=AN81b3nvLGOshSaBIDt4-7lghr1MmFtdTa2XePUll6I,163314
23
23
  cirq/circuits/frozen_circuit.py,sha256=qSbLHqIszCbVipNZQy4N829v_mWf8N2926cYRzpxGqE,9243
24
24
  cirq/circuits/frozen_circuit_test.py,sha256=rHyii8hLhOQ6jdA8dC1OcYPGnyeBC4uY5Q53XspkkCk,4133
25
25
  cirq/circuits/insert_strategy.py,sha256=L0OLXuo24TtBfdJGOAG2PsVDMrbvQl4iN5lUk6IPuyo,2851
@@ -1204,8 +1204,8 @@ cirq/work/sampler.py,sha256=bE5tmVkcR6cZZMLETxDfHehdsYUMbx2RvBeIBetehI4,19187
1204
1204
  cirq/work/sampler_test.py,sha256=hL2UWx3dz2ukZVNxWftiKVvJcQoLplLZdQm-k1QcA40,13282
1205
1205
  cirq/work/zeros_sampler.py,sha256=x1C7cup66a43n-3tm8QjhiqJa07qcJW10FxNp9jJ59Q,2356
1206
1206
  cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
1207
- cirq_core-1.5.0.dev20250311162344.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1208
- cirq_core-1.5.0.dev20250311162344.dist-info/METADATA,sha256=zqDT-r2khy4OAxyTdd0rYP77dcAb2iHlu97tYul5mTA,4817
1209
- cirq_core-1.5.0.dev20250311162344.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
1210
- cirq_core-1.5.0.dev20250311162344.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1211
- cirq_core-1.5.0.dev20250311162344.dist-info/RECORD,,
1207
+ cirq_core-1.5.0.dev20250311225949.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1208
+ cirq_core-1.5.0.dev20250311225949.dist-info/METADATA,sha256=pQGDCqfH1xv6OC-mHsqdBQHwK7iK8xFu-HL4kuehjqo,4817
1209
+ cirq_core-1.5.0.dev20250311225949.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
1210
+ cirq_core-1.5.0.dev20250311225949.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1211
+ cirq_core-1.5.0.dev20250311225949.dist-info/RECORD,,