1# Copyright 2018 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
15from typing import Any, Dict, Sequence, Tuple, TypeVar, TYPE_CHECKING
16
17import abc
18
19from cirq import protocols
20from cirq.ops import pauli_string as ps, raw_types
21
22if TYPE_CHECKING:
23    import cirq
24
25TSelf_PauliStringGateOperation = TypeVar(
26    'TSelf_PauliStringGateOperation', bound='PauliStringGateOperation'
27)
28
29
30class PauliStringGateOperation(raw_types.Operation, metaclass=abc.ABCMeta):
31    def __init__(self, pauli_string: ps.PauliString) -> None:
32        self.pauli_string = pauli_string
33
34    def validate_args(self, qubits: Sequence[raw_types.Qid]) -> None:
35        if len(qubits) != len(self.pauli_string):
36            raise ValueError('Incorrect number of qubits for gate')
37
38    def with_qubits(
39        self: TSelf_PauliStringGateOperation, *new_qubits: 'cirq.Qid'
40    ) -> TSelf_PauliStringGateOperation:
41        self.validate_args(new_qubits)
42        return self.map_qubits(dict(zip(self.pauli_string.qubits, new_qubits)))
43
44    @abc.abstractmethod
45    def map_qubits(
46        self: TSelf_PauliStringGateOperation, qubit_map: Dict[raw_types.Qid, raw_types.Qid]
47    ) -> TSelf_PauliStringGateOperation:
48        """Return an equivalent operation on new qubits with its Pauli string
49        mapped to new qubits.
50
51        new_pauli_string = self.pauli_string.map_qubits(qubit_map)
52        """
53
54    @property
55    def qubits(self) -> Tuple[raw_types.Qid, ...]:
56        return tuple(self.pauli_string)
57
58    def _pauli_string_diagram_info(
59        self,
60        args: 'protocols.CircuitDiagramInfoArgs',
61        exponent: Any = 1,
62    ) -> 'cirq.CircuitDiagramInfo':
63        qubits = self.qubits if args.known_qubits is None else args.known_qubits
64        syms = tuple(f'[{self.pauli_string[qubit]}]' for qubit in qubits)
65        return protocols.CircuitDiagramInfo(wire_symbols=syms, exponent=exponent)
66