Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cirq.convert_to_target_gateset and implementations of CZ, SqrtIswap target gatesets. #5003

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cirq-core/cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,15 @@
from cirq.transformers import (
align_left,
align_right,
CompilationTargetGateset,
CZTargetGateset,
compute_cphase_exponents_for_fsim_decomposition,
convert_to_target_gateset,
decompose_clifford_tableau_to_operations,
decompose_cphase_into_two_fsim,
decompose_multi_controlled_x,
decompose_multi_controlled_rotation,
decompose_operations_to_target_gateset,
decompose_two_qubit_interaction_into_four_fsim_gates,
defer_measurements,
dephase_measurements,
Expand All @@ -382,6 +386,7 @@
merge_single_qubit_moments_to_phxz,
prepare_two_qubit_state_using_cz,
prepare_two_qubit_state_using_sqrt_iswap,
SqrtIswapTargetGateset,
single_qubit_matrix_to_gates,
single_qubit_matrix_to_pauli_rotations,
single_qubit_matrix_to_phased_x_z,
Expand All @@ -398,6 +403,7 @@
two_qubit_matrix_to_operations,
two_qubit_matrix_to_sqrt_iswap_operations,
two_qubit_gate_product_tabulation,
TwoQubitAnalyticalCompilationTarget,
TwoQubitGateTabulation,
TwoQubitGateTabulationResult,
toggle_tags,
Expand Down
3 changes: 3 additions & 0 deletions cirq-core/cirq/protocols/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
'CircuitSampleJob',
'CliffordSimulatorStepResult',
'CliffordTrialResult',
'CompilationTargetGateset',
'CZTargetGateset',
'DensityMatrixSimulator',
'DensityMatrixSimulatorState',
'DensityMatrixStepResult',
Expand Down Expand Up @@ -72,6 +74,7 @@
'TwoQubitDiagonalGate',
'TwoQubitGateTabulationResult',
'UnitSweep',
'SqrtIswapTargetGateset',
'StateVectorSimulatorState',
'StateVectorTrialResult',
'ZerosSampler',
Expand Down
12 changes: 12 additions & 0 deletions cirq-core/cirq/transformers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
two_qubit_gate_product_tabulation,
)

from cirq.transformers.target_gatesets import (
CompilationTargetGateset,
CZTargetGateset,
SqrtIswapTargetGateset,
TwoQubitAnalyticalCompilationTarget,
)

from cirq.transformers.align import align_left, align_right

from cirq.transformers.stratify import stratified_circuit
Expand All @@ -49,6 +56,11 @@

from cirq.transformers.eject_phased_paulis import eject_phased_paulis

from cirq.transformers.convert_to_target_gateset import (
convert_to_target_gateset,
decompose_operations_to_target_gateset,
)

from cirq.transformers.drop_empty_moments import drop_empty_moments

from cirq.transformers.drop_negligible_operations import drop_negligible_operations
Expand Down
123 changes: 123 additions & 0 deletions cirq-core/cirq/transformers/convert_to_target_gateset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Optional, Callable, TYPE_CHECKING

from cirq import protocols
from cirq.transformers.target_gatesets import cz_gateset
from cirq.transformers import transformer_api, transformer_primitives
from cirq.protocols.decompose_protocol import DecomposeResult

if TYPE_CHECKING:
import cirq


def _create_on_stuck_raise_error(gateset: 'cirq.Gateset'):
def _value_error_describing_bad_operation(op: 'cirq.Operation') -> ValueError:
return ValueError(f"Unable to convert {op} to target gateset {gateset!r}")

return _value_error_describing_bad_operation


@transformer_api.transformer
def decompose_operations_to_target_gateset(
circuit: 'cirq.AbstractCircuit',
*,
context: Optional['cirq.TransformerContext'] = None,
gateset: 'cirq.Gateset' = cz_gateset.CZTargetGateset(),
decomposer: Callable[
['cirq.Operation', int], DecomposeResult
] = cz_gateset.CZTargetGateset().decompose_to_target_gateset,
ignore_failures=True,
) -> 'cirq.Circuit':
"""Decomposes every operation to `gateset` using `cirq.decompose` and `decomposer`.

This transformer attempts to decompose every operation `op` in the given circuit to `gateset`
using `cirq.decompose` protocol with `decomposer` used as an intercepting decomposer. This
ensures that `op` is recursively decomposed using implicitly defined known decompositions
(eg: in `_decompose_` magic method on the gaet class) till either `decomposer` knows how to
decompose the given operation or the given operation belongs to `gateset`.

Args:
circuit: Input circuit to transform. It will not be modified.
context: `cirq.TransformerContext` storing common configurable options for transformers.
gateset: Target gateset, which the decomposed operations should belong to.
decomposer: A callable type which accepts an (operation, moment_index) and returns
- An equivalent `cirq.OP_TREE` implementing `op` using gates from `gateset`.
- `None` or `NotImplemented` if does not know how to decompose a given `op`.
ignore_failures: If set, operations that fail to convert are left unchanged. If not set,
conversion failures raise a TypeError.

Returns:
An equivalent circuit containing gates accepted by `gateset`.

Raises:
TypeError: If any input operation fails to convert and `ignore_failures` is False.
"""

def map_func(op: 'cirq.Operation', moment_index: int):
return protocols.decompose(
op,
intercepting_decomposer=lambda o: decomposer(o, moment_index),
keep=gateset._validate_operation,
on_stuck_raise=(None if ignore_failures else _create_on_stuck_raise_error(gateset)),
)

return transformer_primitives.map_operations_and_unroll(
circuit, map_func, tags_to_ignore=context.tags_to_ignore if context else ()
).unfreeze(copy=False)


@transformer_api.transformer
def convert_to_target_gateset(
circuit: 'cirq.AbstractCircuit',
*,
context: Optional['cirq.TransformerContext'] = None,
gateset: 'cirq.CompilationTargetGateset' = cz_gateset.CZTargetGateset(),
ignore_failures: bool = True,
) -> 'cirq.Circuit':
"""Transforms the given circuit into an equivalent circuit using gates accepted by `gateset`.

1. Run all `gateset.preprocess_transformers`
2. Convert operations using built-in cirq decompose + `gateset.decompose_to_target_gateset`.
3. Run all `gateset.postprocess_transformers`

Args:
circuit: Input circuit to transform. It will not be modified.
context: `cirq.TransformerContext` storing common configurable options for transformers.
gateset: Target gateset, which should be an instance of `cirq.CompilationTargetGateset`.
ignore_failures: If set, operations that fail to convert are left unchanged. If not set,
conversion failures raise a TypeError.

Returns:
An equivalent circuit containing gates accepted by `gateset`.

Raises:
TypeError: If any input operation fails to convert and `ignore_failures` is False.
"""
for transformer in gateset.preprocess_transformers:
circuit = transformer(circuit, context=context)

circuit = decompose_operations_to_target_gateset(
circuit,
context=context,
gateset=gateset,
decomposer=gateset.decompose_to_target_gateset,
ignore_failures=ignore_failures,
)

for transformer in gateset.postprocess_transformers:
circuit = transformer(circuit, context=context)

return circuit.unfreeze(copy=False)
24 changes: 24 additions & 0 deletions cirq-core/cirq/transformers/convert_to_target_gateset_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cirq
import pytest


def test_decompose_operations_raises_on_stuck():
c = cirq.Circuit(cirq.X(cirq.NamedQubit("q")))
with pytest.raises(ValueError, match="Unable to convert"):
_ = cirq.decompose_operations_to_target_gateset(
c, gateset=cirq.Gateset(cirq.Y), decomposer=lambda *_: None, ignore_failures=False
)
24 changes: 24 additions & 0 deletions cirq-core/cirq/transformers/target_gatesets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Gatesets which can act as compilation targets in Cirq."""

from cirq.transformers.target_gatesets.compilation_target_gateset import (
CompilationTargetGateset,
TwoQubitAnalyticalCompilationTarget,
)

from cirq.transformers.target_gatesets.cz_gateset import CZTargetGateset

from cirq.transformers.target_gatesets.sqrt_iswap_gateset import SqrtIswapTargetGateset
Loading