Skip to content

Commit 7062846

Browse files
verultCirqBot
andauthored
GoogleCZTargetGateset (#5744)
* Introducing GoogleCZTargetGateset * Change constructor flag to control both eject_z and eject_phased_paulis transformers * Updated testing for eject_paulis * Fix constructor docstring * Split tests to individual gate families * Added more details in class docstring * Raising an op to a power removes tags. Exponentiating the gate instead * Exponentiate on gate instead of TaggedOperation; changed exp value to try to bypass precision error Co-authored-by: Cirq Bot <[email protected]>
1 parent 2be39da commit 7062846

9 files changed

+246
-1
lines changed

cirq-google/cirq_google/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
from cirq_google.transformers import (
9595
known_2q_op_to_sycamore_operations,
9696
two_qubit_matrix_to_sycamore_operations,
97+
GoogleCZTargetGateset,
9798
SycamoreTargetGateset,
9899
)
99100

cirq-google/cirq_google/json_resolver_cache.py

+1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@ def _old_xmon(*args, **kwargs):
8383
# pylint: enable=line-too-long
8484
'cirq.google.EngineResult': cirq_google.EngineResult,
8585
'cirq.google.GridDevice': cirq_google.GridDevice,
86+
'cirq.google.GoogleCZTargetGateset': cirq_google.GoogleCZTargetGateset,
8687
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[
2+
{
3+
"cirq_type": "cirq.google.GoogleCZTargetGateset",
4+
"atol": 1e-08,
5+
"eject_paulis": false,
6+
"additional_gates": []
7+
},
8+
{
9+
"cirq_type": "cirq.google.GoogleCZTargetGateset",
10+
"atol": 1e-06,
11+
"eject_paulis": true,
12+
"additional_gates": [
13+
{
14+
"cirq_type": "GateFamily",
15+
"gate": {
16+
"cirq_type": "ISwapPowGate",
17+
"exponent": 0.5,
18+
"global_shift": 0.0
19+
},
20+
"name": "Instance GateFamily: ISWAP**0.5",
21+
"description": "Accepts `cirq.Gate` instances `g` s.t. `g == ISWAP**0.5`",
22+
"ignore_global_phase": true
23+
},
24+
{
25+
"cirq_type": "GateFamily",
26+
"gate": "XPowGate",
27+
"name": "Type GateFamily: cirq.ops.common_gates.XPowGate",
28+
"description": "Accepts `cirq.Gate` instances `g` s.t. `isinstance(g, cirq.ops.common_gates.XPowGate)`",
29+
"ignore_global_phase": true
30+
}
31+
]
32+
}
33+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[
2+
cirq_google.GoogleCZTargetGateset(atol=1e-08, eject_paulis=False, additional_gates=[]),
3+
cirq_google.GoogleCZTargetGateset(atol=1e-06, eject_paulis=True, additional_gates=[(cirq.ISWAP**0.5), cirq.ops.common_gates.XPowGate])
4+
]

cirq-google/cirq_google/json_test_data/spec.py

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
'SimulatedProcessorWithLocalDeviceRecord',
6363
'EngineResult',
6464
'GridDevice',
65+
'GoogleCZTargetGateset',
6566
]
6667
},
6768
resolver_cache=_class_resolver_dictionary(),

cirq-google/cirq_google/transformers/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
two_qubit_matrix_to_sycamore_operations,
2020
)
2121

22-
from cirq_google.transformers.target_gatesets import SycamoreTargetGateset
22+
from cirq_google.transformers.target_gatesets import GoogleCZTargetGateset, SycamoreTargetGateset

cirq-google/cirq_google/transformers/target_gatesets/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@
1414

1515
"""`cirq.CompilationTargetGateset` implementations for cirq_google gatesets and devices."""
1616

17+
from cirq_google.transformers.target_gatesets.google_cz_gateset import GoogleCZTargetGateset
18+
1719
from cirq_google.transformers.target_gatesets.sycamore_gateset import SycamoreTargetGateset
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Copyright 2022 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 Any, Dict, List, Sequence, Type, Union
16+
import cirq
17+
18+
19+
class GoogleCZTargetGateset(cirq.CZTargetGateset):
20+
"""`cirq.CZTargetGateset` implementation tailored to Google devices.
21+
22+
In addition to features available from `cirq.CZTargetGateset`, `GoogleCZTargetGateset` contains
23+
a flag, `eject_paulis`, to enable the postprocess transformers `cirq.eject_phased_paulis` and
24+
`cirq.eject_z`, which will push X, Y, Z, PhasedX, and certain PhasedXZ gates to the end of the
25+
circuit.
26+
"""
27+
28+
def __init__(
29+
self,
30+
atol: float = 1e-8,
31+
eject_paulis: bool = False,
32+
additional_gates: Sequence[Union[Type[cirq.Gate], cirq.Gate, cirq.GateFamily]] = (),
33+
):
34+
"""Initializes GoogleCZTargetGateset.
35+
36+
Args:
37+
atol: A limit on the amount of absolute error introduced by the transformation.
38+
eject_paulis: Whether to enable postprocess transformers `cirq.eject_z` and
39+
`cirq.eject_phased_paulis`. If enabled, these transformers will remove tags (e.g.
40+
`cirq_google.PhysicalZTag`) from single-qubit Pauli operations. Defaults to False.
41+
additional_gates: Sequence of additional gates / gate families which should also
42+
be "accepted" by this gateset. This is empty by default.
43+
"""
44+
super().__init__(atol=atol, allow_partial_czs=False, additional_gates=additional_gates)
45+
self.eject_paulis = eject_paulis
46+
self._additional_gates_repr_str = ", ".join(
47+
[cirq.ops.gateset._gate_str(g, repr) for g in additional_gates]
48+
)
49+
50+
@property
51+
def postprocess_transformers(self) -> List[cirq.TRANSFORMER]:
52+
"""List of transformers which should be run after decomposing individual operations.
53+
54+
If `eject_paulis` is enabled in the constructor, adds `cirq.eject_phased_paulis` and
55+
`cirq.eject_z` in addition to postprocess_transformers already available in
56+
`cirq.CompilationTargetGateset`.
57+
"""
58+
transformers: List[cirq.TRANSFORMER] = [
59+
cirq.create_transformer_with_kwargs(
60+
cirq.merge_single_qubit_moments_to_phxz, atol=self.atol
61+
),
62+
cirq.create_transformer_with_kwargs(cirq.drop_negligible_operations, atol=self.atol),
63+
cirq.drop_empty_moments,
64+
]
65+
66+
if self.eject_paulis:
67+
return (
68+
transformers[:1]
69+
+ [
70+
cirq.create_transformer_with_kwargs(cirq.eject_phased_paulis, atol=self.atol),
71+
cirq.create_transformer_with_kwargs(cirq.eject_z, atol=self.atol),
72+
]
73+
+ transformers[1:]
74+
)
75+
return transformers
76+
77+
def __repr__(self) -> str:
78+
return (
79+
'cirq_google.GoogleCZTargetGateset('
80+
f'atol={self.atol}, '
81+
f'eject_paulis={self.eject_paulis}, '
82+
f'additional_gates=[{self._additional_gates_repr_str}]'
83+
')'
84+
)
85+
86+
def _value_equality_values_(self) -> Any:
87+
return self.atol, self.eject_paulis, frozenset(self.additional_gates)
88+
89+
@classmethod
90+
def _json_namespace_(cls) -> str:
91+
return 'cirq.google'
92+
93+
def _json_dict_(self) -> Dict[str, Any]:
94+
return {
95+
'atol': self.atol,
96+
'eject_paulis': self.eject_paulis,
97+
'additional_gates': list(self.additional_gates),
98+
}
99+
100+
@classmethod
101+
def _from_json_dict_(cls, atol, eject_paulis, additional_gates, **kwargs):
102+
return cls(atol=atol, eject_paulis=eject_paulis, additional_gates=additional_gates)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright 2022 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 pytest
16+
17+
import cirq
18+
import cirq_google
19+
20+
21+
_qa, _qb = cirq.NamedQubit('a'), cirq.NamedQubit('b')
22+
23+
24+
@pytest.mark.parametrize(
25+
'before, gate_family',
26+
[
27+
(
28+
cirq.Circuit(cirq.Z(_qa) ** 0.5, cirq.CZ(_qa, _qb)),
29+
cirq.GateFamily(cirq.ZPowGate, tags_to_ignore=[cirq_google.PhysicalZTag()]),
30+
),
31+
(
32+
cirq.Circuit(
33+
(cirq.Z**0.5)(_qa).with_tags(cirq_google.PhysicalZTag()), cirq.CZ(_qa, _qb)
34+
),
35+
cirq.GateFamily(cirq.ZPowGate, tags_to_accept=[cirq_google.PhysicalZTag()]),
36+
),
37+
(
38+
cirq.Circuit(cirq.PhasedXPowGate(phase_exponent=0.125).on(_qa), cirq.CZ(_qa, _qb)),
39+
cirq.GateFamily(cirq.PhasedXPowGate),
40+
),
41+
],
42+
)
43+
def test_eject_paulis_disabled(before, gate_family):
44+
after = cirq.optimize_for_target_gateset(
45+
before,
46+
gateset=cirq_google.GoogleCZTargetGateset(additional_gates=[gate_family]),
47+
ignore_failures=False,
48+
)
49+
cirq.testing.assert_same_circuits(after, before)
50+
51+
52+
@pytest.mark.parametrize(
53+
'before, expected, gate_family',
54+
[
55+
(
56+
cirq.Circuit(cirq.Z(_qa) ** 0.75, cirq.CZ(_qa, _qb)),
57+
cirq.Circuit(cirq.CZ(_qa, _qb), cirq.Z(_qa) ** 0.75),
58+
cirq.GateFamily(cirq.ZPowGate, tags_to_ignore=[cirq_google.PhysicalZTag()]),
59+
),
60+
(
61+
# PhysicalZ tag is erased
62+
cirq.Circuit(
63+
(cirq.Z**0.75)(_qa).with_tags(cirq_google.PhysicalZTag()), cirq.CZ(_qa, _qb)
64+
),
65+
cirq.Circuit(cirq.CZ(_qa, _qb), cirq.Z(_qa) ** 0.75),
66+
cirq.GateFamily(cirq.ZPowGate, tags_to_accept=[cirq_google.PhysicalZTag()]),
67+
),
68+
(
69+
cirq.Circuit(cirq.PhasedXPowGate(phase_exponent=0.125).on(_qa), cirq.CZ(_qa, _qb)),
70+
cirq.Circuit(
71+
(cirq.CZ**-1)(_qa, _qb),
72+
cirq.PhasedXPowGate(phase_exponent=0.125).on(_qa),
73+
cirq.Z(_qb),
74+
),
75+
cirq.PhasedXPowGate,
76+
),
77+
],
78+
)
79+
def test_eject_paulis_enabled(before, expected, gate_family):
80+
after = cirq.optimize_for_target_gateset(
81+
before,
82+
gateset=cirq_google.GoogleCZTargetGateset(
83+
eject_paulis=True, additional_gates=[gate_family]
84+
),
85+
ignore_failures=False,
86+
)
87+
cirq.testing.assert_same_circuits(after, expected)
88+
89+
90+
@pytest.mark.parametrize(
91+
'gateset',
92+
[
93+
cirq_google.GoogleCZTargetGateset(),
94+
cirq_google.GoogleCZTargetGateset(
95+
atol=1e-6, eject_paulis=True, additional_gates=[cirq.SQRT_ISWAP, cirq.XPowGate]
96+
),
97+
cirq_google.GoogleCZTargetGateset(additional_gates=()),
98+
],
99+
)
100+
def test_repr(gateset):
101+
cirq.testing.assert_equivalent_repr(gateset, setup_code='import cirq\nimport cirq_google')

0 commit comments

Comments
 (0)