cirq-core 1.3.0.dev20231201164435__py3-none-any.whl → 1.4.0__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.
- cirq/__init__.py +4 -0
- cirq/_compat.py +9 -11
- cirq/_compat_test.py +45 -56
- cirq/_version.py +31 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/circuit.py +13 -8
- cirq/circuits/circuit_operation.py +2 -1
- cirq/circuits/circuit_test.py +2 -2
- cirq/circuits/frozen_circuit.py +3 -2
- cirq/circuits/moment.py +12 -10
- cirq/circuits/qasm_output.py +5 -1
- cirq/circuits/qasm_output_test.py +25 -10
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +9 -7
- cirq/contrib/quimb/mps_simulator_test.py +1 -1
- cirq/contrib/quimb/state_vector.py +9 -2
- cirq/contrib/svg/svg.py +2 -1
- cirq/contrib/svg/svg_test.py +1 -0
- cirq/devices/grid_qubit.py +85 -32
- cirq/devices/grid_qubit_test.py +22 -4
- cirq/devices/line_qubit.py +74 -26
- cirq/devices/line_qubit_test.py +19 -0
- cirq/devices/noise_utils.py +33 -31
- cirq/devices/noise_utils_test.py +1 -84
- cirq/devices/superconducting_qubits_noise_properties.py +7 -6
- cirq/experiments/__init__.py +8 -0
- cirq/experiments/qubit_characterizations.py +288 -44
- cirq/experiments/qubit_characterizations_test.py +61 -7
- cirq/experiments/random_quantum_circuit_generation.py +1 -1
- cirq/experiments/single_qubit_readout_calibration.py +132 -6
- cirq/experiments/single_qubit_readout_calibration_test.py +3 -1
- cirq/experiments/t1_decay_experiment.py +14 -7
- cirq/experiments/t1_decay_experiment_test.py +14 -26
- cirq/experiments/two_qubit_xeb.py +483 -0
- cirq/experiments/two_qubit_xeb_test.py +304 -0
- cirq/json_resolver_cache.py +2 -0
- cirq/linalg/decompositions.py +11 -13
- cirq/linalg/decompositions_test.py +1 -3
- cirq/linalg/diagonalize.py +5 -4
- cirq/linalg/predicates.py +8 -6
- cirq/linalg/transformations.py +2 -1
- cirq/linalg/transformations_test.py +1 -1
- cirq/ops/__init__.py +2 -0
- cirq/ops/clifford_gate.py +59 -16
- cirq/ops/common_gates_test.py +1 -2
- cirq/ops/control_values.py +4 -3
- cirq/ops/controlled_gate_test.py +1 -3
- cirq/ops/gate_operation.py +10 -1
- cirq/ops/named_qubit.py +74 -28
- cirq/ops/named_qubit_test.py +19 -0
- cirq/ops/parity_gates.py +5 -0
- cirq/ops/parity_gates_test.py +2 -10
- cirq/ops/pauli_gates.py +5 -2
- cirq/ops/pauli_string.py +2 -2
- cirq/ops/permutation_gate.py +16 -18
- cirq/ops/phased_iswap_gate_test.py +1 -3
- cirq/ops/phased_x_gate.py +1 -1
- cirq/ops/phased_x_z_gate.py +17 -1
- cirq/ops/phased_x_z_gate_test.py +24 -0
- cirq/ops/qid_util.py +4 -8
- cirq/ops/qubit_manager.py +7 -4
- cirq/ops/qubit_manager_test.py +20 -0
- cirq/ops/raw_types.py +5 -2
- cirq/ops/raw_types_test.py +14 -15
- cirq/ops/uniform_superposition_gate.py +123 -0
- cirq/ops/uniform_superposition_gate_test.py +94 -0
- cirq/protocols/approximate_equality_protocol_test.py +2 -2
- cirq/protocols/circuit_diagram_info_protocol.py +6 -4
- cirq/protocols/commutes_protocol.py +2 -4
- cirq/protocols/decompose_protocol.py +7 -12
- cirq/protocols/decompose_protocol_test.py +7 -3
- cirq/protocols/has_stabilizer_effect_protocol.py +1 -5
- cirq/protocols/has_stabilizer_effect_protocol_test.py +13 -4
- cirq/protocols/json_serialization.py +51 -181
- cirq/protocols/json_serialization_test.py +13 -47
- cirq/protocols/json_test_data/CircuitOperation.json +131 -148
- cirq/protocols/json_test_data/CircuitOperation.json_inward +55 -0
- cirq/protocols/json_test_data/CircuitOperation.repr_inward +6 -0
- cirq/protocols/json_test_data/FrozenCircuit.json +196 -210
- cirq/protocols/json_test_data/FrozenCircuit.json_inward +35 -0
- cirq/protocols/json_test_data/FrozenCircuit.repr_inward +4 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.json +5 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.repr +1 -0
- cirq/protocols/json_test_data/cirq.MSGate.json +4 -0
- cirq/protocols/json_test_data/cirq.MSGate.repr +1 -0
- cirq/protocols/json_test_data/spec.py +2 -0
- cirq/protocols/pow_protocol_test.py +1 -3
- cirq/protocols/resolve_parameters.py +4 -2
- cirq/qis/__init__.py +10 -0
- cirq/qis/clifford_tableau.py +8 -2
- cirq/qis/noise_utils.py +123 -0
- cirq/qis/noise_utils_test.py +97 -0
- cirq/sim/classical_simulator.py +227 -87
- cirq/sim/classical_simulator_test.py +135 -0
- cirq/sim/clifford/clifford_simulator_test.py +4 -2
- cirq/sim/mux.py +5 -3
- cirq/sim/simulation_product_state.py +15 -10
- cirq/sim/simulation_state.py +1 -1
- cirq/sim/simulation_state_test.py +2 -2
- cirq/sim/simulator_base.py +3 -3
- cirq/sim/state_vector_simulation_state.py +4 -4
- cirq/sim/state_vector_simulator.py +17 -2
- cirq/study/__init__.py +1 -0
- cirq/study/result.py +14 -0
- cirq/study/result_test.py +6 -0
- cirq/study/sweeps.py +4 -2
- cirq/study/sweeps_test.py +8 -0
- cirq/testing/__init__.py +6 -1
- cirq/testing/_compat_test_data/__init__.py +3 -3
- cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
- cirq/testing/circuit_compare.py +1 -1
- cirq/testing/consistent_qasm.py +6 -0
- cirq/testing/gate_features.py +10 -0
- cirq/testing/lin_alg_utils.py +5 -3
- cirq/transformers/__init__.py +15 -0
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +3 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +24 -0
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +17 -0
- cirq/transformers/dynamical_decoupling.py +122 -0
- cirq/transformers/dynamical_decoupling_test.py +123 -0
- cirq/transformers/gauge_compiling/__init__.py +26 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +46 -0
- cirq/transformers/gauge_compiling/cz_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +214 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +41 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +83 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +52 -0
- cirq/transformers/gauge_compiling/iswap_gauge.py +105 -0
- cirq/transformers/gauge_compiling/iswap_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +33 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +37 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +64 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +27 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +94 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +22 -0
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -0
- cirq/transformers/merge_k_qubit_gates_test.py +23 -23
- cirq/transformers/merge_single_qubit_gates_test.py +14 -14
- cirq/transformers/optimize_for_target_gateset.py +39 -17
- cirq/transformers/optimize_for_target_gateset_test.py +189 -39
- cirq/transformers/qubit_management_transformers.py +1 -1
- cirq/transformers/routing/visualize_routed_circuit_test.py +17 -17
- cirq/transformers/stratify_test.py +13 -13
- cirq/transformers/target_gatesets/compilation_target_gateset.py +26 -2
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +16 -16
- cirq/transformers/target_gatesets/cz_gateset.py +4 -0
- cirq/transformers/transformer_api.py +1 -2
- cirq/transformers/transformer_primitives.py +15 -14
- cirq/transformers/transformer_primitives_test.py +99 -72
- cirq/value/classical_data.py +6 -6
- cirq/value/value_equality_attr.py +4 -0
- cirq/work/sampler.py +3 -4
- cirq/work/sampler_test.py +25 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
cirq/ops/raw_types_test.py
CHANGED
|
@@ -490,17 +490,17 @@ def test_cannot_remap_non_measurement_gate():
|
|
|
490
490
|
|
|
491
491
|
def test_circuit_diagram():
|
|
492
492
|
class TaggyTag:
|
|
493
|
-
"""Tag with a custom
|
|
493
|
+
"""Tag with a custom str function to test circuit diagrams."""
|
|
494
494
|
|
|
495
|
-
def
|
|
496
|
-
return '
|
|
495
|
+
def __str__(self):
|
|
496
|
+
return '<taggy>'
|
|
497
497
|
|
|
498
498
|
h = cirq.H(cirq.GridQubit(1, 1))
|
|
499
499
|
tagged_h = h.with_tags('tag1')
|
|
500
500
|
non_string_tag_h = h.with_tags(TaggyTag())
|
|
501
501
|
|
|
502
502
|
expected = cirq.CircuitDiagramInfo(
|
|
503
|
-
wire_symbols=("H[
|
|
503
|
+
wire_symbols=("H[tag1]",),
|
|
504
504
|
exponent=1.0,
|
|
505
505
|
connected=True,
|
|
506
506
|
exponent_qubit_index=None,
|
|
@@ -511,14 +511,14 @@ def test_circuit_diagram():
|
|
|
511
511
|
assert cirq.circuit_diagram_info(tagged_h, args) == cirq.circuit_diagram_info(h)
|
|
512
512
|
|
|
513
513
|
c = cirq.Circuit(tagged_h)
|
|
514
|
-
diagram_with_tags = "(1, 1): ───H[
|
|
514
|
+
diagram_with_tags = "(1, 1): ───H[tag1]───"
|
|
515
515
|
diagram_without_tags = "(1, 1): ───H───"
|
|
516
516
|
assert str(cirq.Circuit(tagged_h)) == diagram_with_tags
|
|
517
517
|
assert c.to_text_diagram() == diagram_with_tags
|
|
518
518
|
assert c.to_text_diagram(include_tags=False) == diagram_without_tags
|
|
519
519
|
|
|
520
520
|
c = cirq.Circuit(non_string_tag_h)
|
|
521
|
-
diagram_with_non_string_tag = "(1, 1): ───H[
|
|
521
|
+
diagram_with_non_string_tag = "(1, 1): ───H[<taggy>]───"
|
|
522
522
|
assert c.to_text_diagram() == diagram_with_non_string_tag
|
|
523
523
|
assert c.to_text_diagram(include_tags=False) == diagram_without_tags
|
|
524
524
|
|
|
@@ -531,7 +531,7 @@ def test_circuit_diagram_tagged_global_phase():
|
|
|
531
531
|
# Just global phase in a circuit
|
|
532
532
|
assert cirq.circuit_diagram_info(global_phase, default='default') == 'default'
|
|
533
533
|
cirq.testing.assert_has_diagram(
|
|
534
|
-
cirq.Circuit(global_phase), "\n\nglobal phase: π[
|
|
534
|
+
cirq.Circuit(global_phase), "\n\nglobal phase: π[tag0]", use_unicode_characters=True
|
|
535
535
|
)
|
|
536
536
|
cirq.testing.assert_has_diagram(
|
|
537
537
|
cirq.Circuit(global_phase),
|
|
@@ -558,9 +558,7 @@ def test_circuit_diagram_tagged_global_phase():
|
|
|
558
558
|
no_wire_symbol_op = NoWireSymbols(coefficient=-1.0)().with_tags('tag0')
|
|
559
559
|
assert cirq.circuit_diagram_info(no_wire_symbol_op, default='default') == expected
|
|
560
560
|
cirq.testing.assert_has_diagram(
|
|
561
|
-
cirq.Circuit(no_wire_symbol_op),
|
|
562
|
-
"\n\nglobal phase: π['tag0']",
|
|
563
|
-
use_unicode_characters=True,
|
|
561
|
+
cirq.Circuit(no_wire_symbol_op), "\n\nglobal phase: π[tag0]", use_unicode_characters=True
|
|
564
562
|
)
|
|
565
563
|
|
|
566
564
|
# Two global phases in one moment
|
|
@@ -570,9 +568,9 @@ def test_circuit_diagram_tagged_global_phase():
|
|
|
570
568
|
cirq.testing.assert_has_diagram(
|
|
571
569
|
c,
|
|
572
570
|
"""\
|
|
573
|
-
a: ─────────────X
|
|
571
|
+
a: ─────────────X───────────────
|
|
574
572
|
|
|
575
|
-
global phase: π[
|
|
573
|
+
global phase: π[tag1, tag2]""",
|
|
576
574
|
use_unicode_characters=True,
|
|
577
575
|
precision=2,
|
|
578
576
|
)
|
|
@@ -583,9 +581,9 @@ global phase: π['tag1', 'tag2']""",
|
|
|
583
581
|
cirq.testing.assert_has_diagram(
|
|
584
582
|
c,
|
|
585
583
|
"""\
|
|
586
|
-
a: ─────────────X[
|
|
584
|
+
a: ─────────────X[x_tag]─────X────────────
|
|
587
585
|
|
|
588
|
-
global phase: 0.5π[
|
|
586
|
+
global phase: 0.5π[tag1] 0.5π[tag2]
|
|
589
587
|
""",
|
|
590
588
|
use_unicode_characters=True,
|
|
591
589
|
include_tags=True,
|
|
@@ -603,7 +601,7 @@ def test_circuit_diagram_no_circuit_diagram():
|
|
|
603
601
|
q = cirq.GridQubit(1, 1)
|
|
604
602
|
expected = "(1, 1): ───guess-i-will-repr───"
|
|
605
603
|
assert cirq.Circuit(NoCircuitDiagram()(q)).to_text_diagram() == expected
|
|
606
|
-
expected = "(1, 1): ───guess-i-will-repr[
|
|
604
|
+
expected = "(1, 1): ───guess-i-will-repr[taggy]───"
|
|
607
605
|
assert cirq.Circuit(NoCircuitDiagram()(q).with_tags('taggy')).to_text_diagram() == expected
|
|
608
606
|
|
|
609
607
|
|
|
@@ -761,6 +759,7 @@ def test_inverse_composite_standards():
|
|
|
761
759
|
assert cirq.parameter_names(g) == {'a'}
|
|
762
760
|
assert cirq.resolve_parameters(g, {a: 0}) == Gate(0) ** -1
|
|
763
761
|
cirq.testing.assert_implements_consistent_protocols(g, global_vals={'C': Gate, 'a': a})
|
|
762
|
+
assert str(g) == 'C(a)†'
|
|
764
763
|
|
|
765
764
|
|
|
766
765
|
def test_tagged_act_on():
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Copyright 2024 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 Sequence, Any, Dict, TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from cirq.ops.common_gates import H, ry
|
|
19
|
+
from cirq.ops.pauli_gates import X
|
|
20
|
+
from cirq.ops import raw_types
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
import cirq
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class UniformSuperpositionGate(raw_types.Gate):
|
|
28
|
+
r"""Creates a uniform superposition state on the states $[0, M)$
|
|
29
|
+
The gate creates the state $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$
|
|
30
|
+
(where $1\leq M \leq 2^n$), using n qubits, according to the Shukla-Vedula algorithm [SV24].
|
|
31
|
+
References:
|
|
32
|
+
[SV24]
|
|
33
|
+
[An efficient quantum algorithm for preparation of uniform quantum superposition
|
|
34
|
+
states](https://arxiv.org/abs/2306.11747)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, m_value: int, num_qubits: int) -> None:
|
|
38
|
+
"""Initializes UniformSuperpositionGate.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
m_value: The number of computational basis states.
|
|
42
|
+
num_qubits: The number of qubits used.
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
ValueError: If `m_value` is not a positive integer, or
|
|
46
|
+
if `num_qubits` is not an integer greater than or equal to log2(m_value).
|
|
47
|
+
"""
|
|
48
|
+
if not (isinstance(m_value, int) and (m_value > 0)):
|
|
49
|
+
raise ValueError("m_value must be a positive integer.")
|
|
50
|
+
log_two_m_value = m_value.bit_length()
|
|
51
|
+
|
|
52
|
+
if (m_value & (m_value - 1)) == 0:
|
|
53
|
+
log_two_m_value = log_two_m_value - 1
|
|
54
|
+
if not (isinstance(num_qubits, int) and (num_qubits >= log_two_m_value)):
|
|
55
|
+
raise ValueError(
|
|
56
|
+
"num_qubits must be an integer greater than or equal to log2(m_value)."
|
|
57
|
+
)
|
|
58
|
+
self._m_value = m_value
|
|
59
|
+
self._num_qubits = num_qubits
|
|
60
|
+
|
|
61
|
+
def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE":
|
|
62
|
+
"""Decomposes the gate into a sequence of standard gates.
|
|
63
|
+
Implements the construction from https://arxiv.org/pdf/2306.11747.
|
|
64
|
+
"""
|
|
65
|
+
qreg = list(qubits)
|
|
66
|
+
qreg.reverse()
|
|
67
|
+
|
|
68
|
+
if self._m_value == 1: # if m_value is 1, do nothing
|
|
69
|
+
return
|
|
70
|
+
if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2
|
|
71
|
+
m = self._m_value.bit_length() - 1
|
|
72
|
+
yield H.on_each(qreg[:m])
|
|
73
|
+
return
|
|
74
|
+
k = self._m_value.bit_length()
|
|
75
|
+
l_value = []
|
|
76
|
+
for i in range(self._m_value.bit_length()):
|
|
77
|
+
if (self._m_value >> i) & 1:
|
|
78
|
+
l_value.append(i) # Locations of '1's
|
|
79
|
+
|
|
80
|
+
yield X.on_each(qreg[q_bit] for q_bit in l_value[1:k])
|
|
81
|
+
m_current = 2 ** (l_value[0])
|
|
82
|
+
theta = -2 * np.arccos(np.sqrt(m_current / self._m_value))
|
|
83
|
+
if l_value[0] > 0: # if m_value is even
|
|
84
|
+
yield H.on_each(qreg[: l_value[0]])
|
|
85
|
+
|
|
86
|
+
yield ry(theta).on(qreg[l_value[1]])
|
|
87
|
+
|
|
88
|
+
for i in range(l_value[0], l_value[1]):
|
|
89
|
+
yield H(qreg[i]).controlled_by(qreg[l_value[1]], control_values=[False])
|
|
90
|
+
|
|
91
|
+
for m in range(1, len(l_value) - 1):
|
|
92
|
+
theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current)))
|
|
93
|
+
yield ry(theta).on(qreg[l_value[m + 1]]).controlled_by(
|
|
94
|
+
qreg[l_value[m]], control_values=[0]
|
|
95
|
+
)
|
|
96
|
+
for i in range(l_value[m], l_value[m + 1]):
|
|
97
|
+
yield H.on(qreg[i]).controlled_by(qreg[l_value[m + 1]], control_values=[0])
|
|
98
|
+
|
|
99
|
+
m_current = m_current + 2 ** (l_value[m])
|
|
100
|
+
|
|
101
|
+
def num_qubits(self) -> int:
|
|
102
|
+
return self._num_qubits
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def m_value(self) -> int:
|
|
106
|
+
return self._m_value
|
|
107
|
+
|
|
108
|
+
def __eq__(self, other):
|
|
109
|
+
if isinstance(other, UniformSuperpositionGate):
|
|
110
|
+
return (self._m_value == other._m_value) and (self._num_qubits == other._num_qubits)
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def __repr__(self) -> str:
|
|
114
|
+
return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})'
|
|
115
|
+
|
|
116
|
+
def _json_dict_(self) -> Dict[str, Any]:
|
|
117
|
+
d = {}
|
|
118
|
+
d['m_value'] = self._m_value
|
|
119
|
+
d['num_qubits'] = self._num_qubits
|
|
120
|
+
return d
|
|
121
|
+
|
|
122
|
+
def __str__(self) -> str:
|
|
123
|
+
return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright 2024 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 numpy as np
|
|
16
|
+
import pytest
|
|
17
|
+
import cirq
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.mark.parametrize(
|
|
21
|
+
["m", "n"],
|
|
22
|
+
[[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)]
|
|
23
|
+
+ [(1, 2), (4, 2), (6, 3), (7, 3)],
|
|
24
|
+
)
|
|
25
|
+
def test_generated_unitary_is_uniform(m: int, n: int) -> None:
|
|
26
|
+
r"""The code checks that the unitary matrix corresponds to the generated uniform superposition
|
|
27
|
+
states (see uniform_superposition_gate.py). It is enough to check that the
|
|
28
|
+
first colum of the unitary matrix (which corresponds to the action of the gate on
|
|
29
|
+
$\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$
|
|
30
|
+
entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the
|
|
31
|
+
remaining $2^n-M$ entries are all "0"s.
|
|
32
|
+
"""
|
|
33
|
+
gate = cirq.UniformSuperpositionGate(m, n)
|
|
34
|
+
matrix = np.array(cirq.unitary(gate))
|
|
35
|
+
np.testing.assert_allclose(
|
|
36
|
+
matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.parametrize(["m", "n"], [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)])
|
|
41
|
+
def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None:
|
|
42
|
+
r"""The code checks that test errors are raised if the arguments m (number of
|
|
43
|
+
superposition states and n (number of qubits) are positive integers and are compatible
|
|
44
|
+
(i.e., n >= log2(m)).
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
if not (isinstance(m, int)):
|
|
48
|
+
with pytest.raises(ValueError, match="m_value must be a positive integer."):
|
|
49
|
+
cirq.UniformSuperpositionGate(m, n)
|
|
50
|
+
elif not (isinstance(n, int)):
|
|
51
|
+
with pytest.raises(
|
|
52
|
+
ValueError,
|
|
53
|
+
match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).",
|
|
54
|
+
):
|
|
55
|
+
cirq.UniformSuperpositionGate(m, n)
|
|
56
|
+
elif m < 1:
|
|
57
|
+
with pytest.raises(ValueError, match="m_value must be a positive integer."):
|
|
58
|
+
cirq.UniformSuperpositionGate(int(m), int(n))
|
|
59
|
+
elif n < np.log2(m):
|
|
60
|
+
with pytest.raises(
|
|
61
|
+
ValueError,
|
|
62
|
+
match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).",
|
|
63
|
+
):
|
|
64
|
+
cirq.UniformSuperpositionGate(m, n)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_repr():
|
|
68
|
+
assert (
|
|
69
|
+
repr(cirq.UniformSuperpositionGate(7, 3))
|
|
70
|
+
== 'UniformSuperpositionGate(m_value=7, num_qubits=3)'
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_uniform_superposition_gate_json_dict():
|
|
75
|
+
assert cirq.UniformSuperpositionGate(7, 3)._json_dict_() == {'m_value': 7, 'num_qubits': 3}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_str():
|
|
79
|
+
assert (
|
|
80
|
+
str(cirq.UniformSuperpositionGate(7, 3))
|
|
81
|
+
== 'UniformSuperpositionGate(m_value=7, num_qubits=3)'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@pytest.mark.parametrize(["m", "n"], [(5, 3), (10, 4)])
|
|
86
|
+
def test_eq(m: int, n: int) -> None:
|
|
87
|
+
a = cirq.UniformSuperpositionGate(m, n)
|
|
88
|
+
b = cirq.UniformSuperpositionGate(m, n)
|
|
89
|
+
c = cirq.UniformSuperpositionGate(m + 1, n)
|
|
90
|
+
d = cirq.X
|
|
91
|
+
assert a.m_value == b.m_value
|
|
92
|
+
assert a.__eq__(b)
|
|
93
|
+
assert not (a.__eq__(c))
|
|
94
|
+
assert not (a.__eq__(d))
|
|
@@ -47,11 +47,11 @@ def test_approx_eq_mixed_primitives():
|
|
|
47
47
|
|
|
48
48
|
def test_numpy_dtype_compatibility():
|
|
49
49
|
i_a, i_b, i_c = 0, 1, 2
|
|
50
|
-
i_types = [np.intc, np.intp, np.
|
|
50
|
+
i_types = [np.intc, np.intp, np.int8, np.int16, np.int32, np.int64]
|
|
51
51
|
for i_type in i_types:
|
|
52
52
|
assert cirq.approx_eq(i_type(i_a), i_type(i_b), atol=1)
|
|
53
53
|
assert not cirq.approx_eq(i_type(i_a), i_type(i_c), atol=1)
|
|
54
|
-
u_types = [np.uint, np.
|
|
54
|
+
u_types = [np.uint, np.uintp, np.uint8, np.uint16, np.uint32, np.uint64]
|
|
55
55
|
for u_type in u_types:
|
|
56
56
|
assert cirq.approx_eq(u_type(i_a), u_type(i_b), atol=1)
|
|
57
57
|
assert not cirq.approx_eq(u_type(i_a), u_type(i_c), atol=1)
|
|
@@ -221,9 +221,11 @@ class CircuitDiagramInfoArgs:
|
|
|
221
221
|
self.known_qubit_count,
|
|
222
222
|
self.use_unicode_characters,
|
|
223
223
|
self.precision,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
(
|
|
225
|
+
None
|
|
226
|
+
if self.label_map is None
|
|
227
|
+
else tuple(sorted(self.label_map.items(), key=lambda e: e[0]))
|
|
228
|
+
),
|
|
227
229
|
self.include_tags,
|
|
228
230
|
self.transpose,
|
|
229
231
|
)
|
|
@@ -354,7 +356,7 @@ def _op_info_with_fallback(
|
|
|
354
356
|
|
|
355
357
|
# Add tags onto the representation, if they exist
|
|
356
358
|
if op.tags:
|
|
357
|
-
name += f'
|
|
359
|
+
name += f"[{', '.join(map(str, op.tags))}]"
|
|
358
360
|
|
|
359
361
|
# Include ordering in the qubit labels.
|
|
360
362
|
symbols = (name,) + tuple(f'#{i + 1}' for i in range(1, len(op.qubits)))
|
|
@@ -74,15 +74,13 @@ class SupportsCommutes(Protocol):
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
@overload
|
|
77
|
-
def commutes(v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8) -> bool:
|
|
78
|
-
...
|
|
77
|
+
def commutes(v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8) -> bool: ...
|
|
79
78
|
|
|
80
79
|
|
|
81
80
|
@overload
|
|
82
81
|
def commutes(
|
|
83
82
|
v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8, default: TDefault
|
|
84
|
-
) -> Union[bool, TDefault]:
|
|
85
|
-
...
|
|
83
|
+
) -> Union[bool, TDefault]: ...
|
|
86
84
|
|
|
87
85
|
|
|
88
86
|
def commutes(
|
|
@@ -57,8 +57,7 @@ _CONTEXT_COUNTER = itertools.count() # Use _reset_context_counter() to reset th
|
|
|
57
57
|
class OpDecomposerWithContext(Protocol):
|
|
58
58
|
def __call__(
|
|
59
59
|
self, __op: 'cirq.Operation', *, context: Optional['cirq.DecompositionContext'] = None
|
|
60
|
-
) -> DecomposeResult:
|
|
61
|
-
...
|
|
60
|
+
) -> DecomposeResult: ...
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
OpDecomposer = Union[Callable[['cirq.Operation'], DecomposeResult], OpDecomposerWithContext]
|
|
@@ -93,16 +92,12 @@ class SupportsDecompose(Protocol):
|
|
|
93
92
|
"""An object that can be decomposed into simpler operations.
|
|
94
93
|
|
|
95
94
|
All decomposition methods should ultimately terminate on basic 1-qubit and
|
|
96
|
-
2-qubit gates included by default in Cirq.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
and
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
instead of specific gate types such as CZ gates (though a consumer is
|
|
103
|
-
of course free to handle CZ gates in a special way, and consumers can
|
|
104
|
-
give an `intercepting_decomposer` to `cirq.decompose` that attempts to
|
|
105
|
-
target a specific gate set).
|
|
95
|
+
2-qubit gates included by default in Cirq. If a custom decomposition is not
|
|
96
|
+
specified, Cirq will decompose all operations to XPow/YPow/ZPow/CZPow/Measurement
|
|
97
|
+
+ Global phase gateset. However, the default decomposition in Cirq should be a last resort
|
|
98
|
+
fallback and it is recommended for consumers of decomposition to either not depend
|
|
99
|
+
upon a specific target gateset, or give an `intercepting_decomposer` to `cirq.decompose`
|
|
100
|
+
that attempts to target a specific gate set.
|
|
106
101
|
|
|
107
102
|
For example, `cirq.TOFFOLI` has a `_decompose_` method that returns a pair
|
|
108
103
|
of Hadamard gates surrounding a `cirq.CCZ`. Although `cirq.CCZ` is not a
|
|
@@ -346,9 +346,13 @@ class RecursiveDecompose(cirq.Gate):
|
|
|
346
346
|
|
|
347
347
|
def _decompose_impl(self, qubits, mock_qm: mock.Mock):
|
|
348
348
|
mock_qm.qalloc(self.recurse)
|
|
349
|
-
yield
|
|
350
|
-
|
|
351
|
-
|
|
349
|
+
yield (
|
|
350
|
+
RecursiveDecompose(
|
|
351
|
+
recurse=False, mock_qm=self.mock_qm, with_context=self.with_context
|
|
352
|
+
).on(*qubits)
|
|
353
|
+
if self.recurse
|
|
354
|
+
else cirq.Z.on_each(*qubits)
|
|
355
|
+
)
|
|
352
356
|
mock_qm.qfree(self.recurse)
|
|
353
357
|
|
|
354
358
|
def _decompose_(self, qubits):
|
|
@@ -102,11 +102,7 @@ def _strat_has_stabilizer_effect_from_unitary(val: Any) -> Optional[bool]:
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def _strat_has_stabilizer_effect_from_decompose(val: Any) -> Optional[bool]:
|
|
105
|
-
|
|
106
|
-
if qid_shape is None or len(qid_shape) <= 3:
|
|
107
|
-
return None
|
|
108
|
-
|
|
109
|
-
decomposition = decompose_protocol.decompose_once(val, default=None)
|
|
105
|
+
decomposition, _, _ = decompose_protocol._try_decompose_into_operations_and_qubits(val)
|
|
110
106
|
if decomposition is None:
|
|
111
107
|
return None
|
|
112
108
|
for op in decomposition:
|
|
@@ -41,15 +41,15 @@ class Yes:
|
|
|
41
41
|
return True
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
q = cirq.LineQubit(0)
|
|
45
|
-
|
|
46
|
-
|
|
47
44
|
class EmptyOp(cirq.Operation):
|
|
48
45
|
"""A trivial operation."""
|
|
49
46
|
|
|
47
|
+
def __init__(self, q: cirq.Qid = cirq.LineQubit(0)):
|
|
48
|
+
self.q = q
|
|
49
|
+
|
|
50
50
|
@property
|
|
51
51
|
def qubits(self):
|
|
52
|
-
return (q,)
|
|
52
|
+
return (self.q,)
|
|
53
53
|
|
|
54
54
|
def with_qubits(self, *new_qubits): # pragma: no cover
|
|
55
55
|
return self
|
|
@@ -97,6 +97,14 @@ class OpWithUnitary(EmptyOp):
|
|
|
97
97
|
return cirq.LineQubit.range(self.unitary.shape[0].bit_length() - 1)
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
class GateDecomposes(cirq.Gate):
|
|
101
|
+
def _num_qubits_(self):
|
|
102
|
+
return 1
|
|
103
|
+
|
|
104
|
+
def _decompose_(self, qubits):
|
|
105
|
+
yield YesOp(*qubits)
|
|
106
|
+
|
|
107
|
+
|
|
100
108
|
def test_inconclusive():
|
|
101
109
|
assert not cirq.has_stabilizer_effect(object())
|
|
102
110
|
assert not cirq.has_stabilizer_effect('boo')
|
|
@@ -146,3 +154,4 @@ def test_via_decompose():
|
|
|
146
154
|
assert not cirq.has_stabilizer_effect(
|
|
147
155
|
OpWithUnitary(cirq.unitary(cirq.Circuit(cirq.T.on_each(cirq.LineQubit.range(4)))))
|
|
148
156
|
)
|
|
157
|
+
assert cirq.has_stabilizer_effect(GateDecomposes())
|