Skip to content

Commit 43701fb

Browse files
authored
Merge branch 'master' into cg-device-refactor/measure-two-qubits
2 parents d41c8ce + de3907c commit 43701fb

File tree

10 files changed

+96
-30
lines changed

10 files changed

+96
-30
lines changed

cirq-core/cirq/contrib/quantum_volume/quantum_volume.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,6 @@ def process_results(
197197
return data
198198

199199

200-
class SwapPermutationReplacer(cirq.PointOptimizer):
201-
"""Replaces SwapPermutationGates with their underlying implementation
202-
gate."""
203-
204-
def __init__(self):
205-
super().__init__()
206-
207-
def optimization_at(
208-
self, circuit: cirq.Circuit, index: int, op: cirq.Operation
209-
) -> Optional[cirq.PointOptimizationSummary]:
210-
if isinstance(op.gate, cirq.contrib.acquaintance.SwapPermutationGate):
211-
new_ops = op.gate.swap_gate.on(*op.qubits)
212-
return cirq.PointOptimizationSummary(
213-
clear_span=1, clear_qubits=op.qubits, new_operations=new_ops
214-
)
215-
return None # Don't make changes to other gates.
216-
217-
218200
def compile_circuit(
219201
circuit: cirq.Circuit,
220202
*,
@@ -296,7 +278,15 @@ def compile_circuit(
296278
mapping = swap_networks[0].final_mapping()
297279
# Replace the PermutationGates with regular gates, so we don't proliferate
298280
# the routing implementation details to the compiler and the device itself.
299-
SwapPermutationReplacer().optimize_circuit(routed_circuit)
281+
282+
def replace_swap_permutation_gate(op: 'cirq.Operation', _):
283+
if isinstance(op.gate, cirq.contrib.acquaintance.SwapPermutationGate):
284+
return [op.gate.swap_gate.on(*op.qubits)]
285+
return op
286+
287+
routed_circuit = cirq.map_operations_and_unroll(
288+
routed_circuit, map_func=replace_swap_permutation_gate
289+
)
300290

301291
if not compiler:
302292
return CompilationResult(circuit=routed_circuit, mapping=mapping, parity_map=parity_map)
@@ -307,7 +297,7 @@ def compile_circuit(
307297
# as well, we allow this to be passed in. This compiler is not allowed to
308298
# change the order of the qubits.
309299
return CompilationResult(
310-
circuit=compiler(swap_networks[0].circuit), mapping=mapping, parity_map=parity_map
300+
circuit=compiler(routed_circuit), mapping=mapping, parity_map=parity_map
311301
)
312302

313303

cirq-core/cirq/ops/global_phase_op.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,17 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
"""A no-qubit global phase operation."""
15-
from typing import AbstractSet, Any, Dict, Sequence, Tuple, TYPE_CHECKING, Union
15+
16+
from typing import AbstractSet, Any, cast, Dict, Sequence, Tuple, Union
1617

1718
import numpy as np
1819
import sympy
1920

21+
import cirq
2022
from cirq import value, protocols
2123
from cirq.ops import raw_types
2224
from cirq.type_workarounds import NotImplementedType
2325

24-
if TYPE_CHECKING:
25-
import cirq
26-
2726

2827
@value.value_equality(approximate=True)
2928
class GlobalPhaseGate(raw_types.Gate):
@@ -57,7 +56,8 @@ def _apply_unitary_(
5756
) -> Union[np.ndarray, NotImplementedType]:
5857
if not self._has_unitary_():
5958
return NotImplemented
60-
args.target_tensor *= self.coefficient
59+
assert not cirq.is_parameterized(self)
60+
args.target_tensor *= cast(np.generic, self.coefficient)
6161
return args.target_tensor
6262

6363
def _has_stabilizer_effect_(self) -> bool:

cirq-core/cirq/ops/pauli_string.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import numpy as np
4242
import sympy
4343

44+
import cirq
4445
from cirq import value, protocols, linalg, qis
4546
from cirq._doc import document
4647
from cirq._import import LazyLoader
@@ -498,9 +499,15 @@ def matrix(self, qubits: Optional[Iterable[TKey]] = None) -> np.ndarray:
498499
in which the matrix representation of the Pauli string is to
499500
be computed. Qubits absent from `self.qubits` are acted on by
500501
the identity. Defaults to `self.qubits`.
502+
503+
Raises:
504+
NotImplementedError: If this PauliString is parameterized.
501505
"""
502506
qubits = self.qubits if qubits is None else qubits
503507
factors = [self.get(q, default=identity.I) for q in qubits]
508+
if cirq.is_parameterized(self):
509+
raise NotImplementedError('Cannot express as matrix when parameterized')
510+
assert isinstance(self.coefficient, complex)
504511
return linalg.kron(self.coefficient, *[protocols.unitary(f) for f in factors])
505512

506513
def _has_unitary_(self) -> bool:
@@ -516,6 +523,7 @@ def _unitary_(self) -> Optional[np.ndarray]:
516523
def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'):
517524
if not self._has_unitary_():
518525
return None
526+
assert isinstance(self.coefficient, complex)
519527
if self.coefficient != 1:
520528
args.target_tensor *= self.coefficient
521529
return protocols.apply_unitaries([self[q].on(q) for q in self.qubits], self.qubits, args)

cirq-core/cirq/ops/pauli_string_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,6 +1985,8 @@ def test_parameterization():
19851985
pst.expectation_from_state_vector(np.array([]), {})
19861986
with pytest.raises(NotImplementedError, match='parameterized'):
19871987
pst.expectation_from_density_matrix(np.array([]), {})
1988+
with pytest.raises(NotImplementedError, match='as matrix when parameterized'):
1989+
pst.matrix()
19881990
assert pst**1 == pst
19891991
assert pst**-1 == pst.with_coefficient(1.0 / t)
19901992
assert (-pst) ** 1 == -pst

cirq-core/cirq/ops/phased_iswap_gate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
"""ISWAPPowGate conjugated by tensor product Rz(phi) and Rz(-phi)."""
1515

16-
from typing import AbstractSet, Any, Dict, List, Optional, Sequence, Tuple, Union
16+
from typing import AbstractSet, Any, cast, Dict, List, Optional, Sequence, Tuple, Union
1717

1818
import numpy as np
1919
import sympy
@@ -173,7 +173,7 @@ def _pauli_expansion_(self) -> value.LinearDict[str]:
173173
return NotImplemented
174174
expansion = protocols.pauli_expansion(self._iswap)
175175
assert set(expansion.keys()).issubset({'II', 'XX', 'YY', 'ZZ'})
176-
assert np.isclose(expansion['XX'], expansion['YY'])
176+
assert np.isclose(cast(np.generic, expansion['XX']), cast(np.generic, expansion['YY']))
177177

178178
v = (expansion['XX'] + expansion['YY']) / 2
179179
phase_angle = np.pi * self.phase_exponent

cirq-google/cirq_google/engine/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
from cirq_google.engine.validating_sampler import ValidatingSampler
7373

7474
from cirq_google.engine.virtual_engine_factory import (
75+
create_default_noisy_quantum_virtual_machine,
7576
create_device_from_processor_id,
7677
create_noiseless_virtual_engine_from_device,
7778
create_noiseless_virtual_engine_from_proto,

cirq-google/cirq_google/engine/virtual_engine_factory.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414

1515
"""Functions to instantiate SimulatedLocalEngines to simulate various Google Devices."""
1616
import json
17-
from typing import cast, Iterable, List, Optional, Union
17+
from typing import cast, Iterable, List, Optional, Union, Type
1818
import pathlib
1919
import time
2020

2121
import google.protobuf.text_format as text_format
2222
import cirq
23+
from cirq.sim.simulator import SimulatesSamples
2324
from cirq_google.api import v2
2425
from cirq_google.engine import calibration, engine_validator, simulated_local_processor, util
2526
from cirq_google.devices import grid_device
27+
from cirq_google.devices.google_noise_properties import NoiseModelFromGoogleNoiseProperties
2628
from cirq_google.serialization import serializable_gate_set
29+
from cirq_google.engine.calibration_to_noise_properties import noise_properties_from_calibration
2730
from cirq_google.engine.simulated_local_engine import SimulatedLocalEngine
2831
from cirq_google.engine.simulated_local_processor import SimulatedLocalProcessor
2932

@@ -367,3 +370,44 @@ def create_noiseless_virtual_engine_from_latest_templates() -> SimulatedLocalEng
367370
processor_ids = list(MOST_RECENT_TEMPLATES.keys())
368371
template_names = [MOST_RECENT_TEMPLATES[k] for k in processor_ids]
369372
return create_noiseless_virtual_engine_from_templates(processor_ids, template_names)
373+
374+
375+
def create_default_noisy_quantum_virtual_machine(
376+
processor_id: str, simulator_class: Type[SimulatesSamples] = None, **kwargs
377+
) -> SimulatedLocalEngine:
378+
"""Creates a virtual engine with a noisy simulator based on a processor id.
379+
380+
Args:
381+
processor_id: The string name of a processor that has available noise data.
382+
simulator_class: The class of the type of simulator to be initialized. The
383+
simulator class initializer needs to support the `noise` parameter.
384+
kwargs: Other arguments which are passed through to the simulator initializer.
385+
The 'noise' argument will be overwritten with a new noise model.
386+
387+
Returns:
388+
A SimulatedLocalEngine that uses a simulator of type simulator_class with a
389+
noise model based on available noise data for the processor processor_id.
390+
"""
391+
392+
if simulator_class is None:
393+
try: # coverage: ignore
394+
import qsimcirq # type: ignore
395+
396+
simulator_class = qsimcirq.Simulator # coverage: ignore
397+
except ImportError:
398+
simulator_class = cirq.Simulator # coverage: ignore
399+
400+
calibration = load_median_device_calibration(processor_id)
401+
noise_properties = noise_properties_from_calibration(calibration)
402+
noise_model = NoiseModelFromGoogleNoiseProperties(noise_properties)
403+
simulator = simulator_class(noise=noise_model, **kwargs) # type: ignore
404+
405+
device = create_device_from_processor_id(processor_id)
406+
simulated_processor = SimulatedLocalProcessor(
407+
processor_id=processor_id,
408+
sampler=simulator,
409+
device=device,
410+
calibrations={calibration.timestamp // 1000: calibration},
411+
)
412+
413+
return SimulatedLocalEngine([simulated_processor])

cirq-google/cirq_google/engine/virtual_engine_factory_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,19 @@ def test_create_from_proto_no_qubits():
175175
_ = factory.create_noiseless_virtual_engine_from_device(
176176
'sycamore', cirq.UNCONSTRAINED_DEVICE
177177
)
178+
179+
180+
def test_create_default_noisy_quantum_virtual_machine():
181+
for processor_id in ["rainbow", "weber"]:
182+
engine = factory.create_default_noisy_quantum_virtual_machine(
183+
processor_id=processor_id, simulator_class=cirq.Simulator
184+
)
185+
processor = engine.get_processor(processor_id)
186+
bad_qubit = cirq.GridQubit(10, 10)
187+
circuit = cirq.Circuit(cirq.X(bad_qubit), cirq.measure(bad_qubit))
188+
with pytest.raises(ValueError, match='Qubit not on device'):
189+
_ = processor.run(circuit, repetitions=100)
190+
good_qubit = cirq.GridQubit(5, 4)
191+
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
192+
with pytest.raises(ValueError, match='.* contains a gate which is not supported.'):
193+
_ = processor.run(circuit, repetitions=100)

cirq-rigetti/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pydantic~=1.8.2
99
pyjwt~=1.7.1
1010
pyquil~=2.28.2; python_version < "3.7"
1111
pyquil~=3.0.0; python_version >= "3.7"
12+
# Remove once https://github.com/python-rapidjson/python-rapidjson/issues/166 is resolved.
13+
python-rapidjson<=1.6
1214
python-dateutil~=2.8.1
1315
qcs-api-client~=0.8.0
1416
retrying~=1.3.3

docs/dev/development.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ Note that if you are using PyCharm, you might have to Restart & Invalidate Cache
2828

2929
```bash
3030
docker build -t cirq --target cirq_stable .
31-
docker run -it cirq python -c "import cirq_google; print(cirq_google.Foxtail)"
31+
docker run -it cirq python -c "import cirq_google; print(cirq_google.Sycamore23)"
3232
```
3333

3434
```bash
3535
docker build -t cirq_pre --target cirq_pre_release .
36-
docker run -it cirq_pre python -c "import cirq_google; print(cirq_google.Foxtail)"
36+
docker run -it cirq_pre python -c "import cirq_google; print(cirq_google.Sycamore23)"
3737
```
3838

3939
If you want to contribute changes to Cirq, you will instead want to fork the repository and submit pull requests from your fork.
@@ -85,6 +85,9 @@ At this point your local git master should be synced with the master from the ma
8585

8686
## Setting up an environment
8787

88+
These instructions are primarily for linux-based environments that use the apt
89+
package manager.
90+
8891
0. First clone the repository, if you have not already done so.
8992
See the previous section for instructions.
9093

0 commit comments

Comments
 (0)