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
15"""Common quantum gates that target three qubits."""
16
17from typing import (
18    AbstractSet,
19    Any,
20    Collection,
21    List,
22    Optional,
23    Sequence,
24    Tuple,
25    TYPE_CHECKING,
26    Union,
27)
28
29import numpy as np
30import sympy
31
32from cirq import linalg, protocols, value
33from cirq._compat import proper_repr
34from cirq._doc import document
35from cirq.ops import (
36    common_gates,
37    controlled_gate,
38    eigen_gate,
39    gate_features,
40    pauli_gates,
41    raw_types,
42    swap_gates,
43    raw_types,
44)
45
46if TYPE_CHECKING:
47    # pylint: disable=unused-import
48    import cirq
49
50
51class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
52    """A doubly-controlled-Z that can be raised to a power.
53
54    The matrix of `CCZ**t` is `diag(1, 1, 1, 1, 1, 1, 1, exp(i pi t))`.
55    """
56
57    def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
58        return [
59            (0, np.diag([1, 1, 1, 1, 1, 1, 1, 0])),
60            (1, np.diag([0, 0, 0, 0, 0, 0, 0, 1])),
61        ]
62
63    def _trace_distance_bound_(self) -> Optional[float]:
64        if self._is_parameterized_():
65            return None
66        return abs(np.sin(self._exponent * 0.5 * np.pi))
67
68    def _pauli_expansion_(self) -> value.LinearDict[str]:
69        if protocols.is_parameterized(self):
70            return NotImplemented
71        global_phase = 1j ** (2 * self._exponent * self._global_shift)
72        z_phase = 1j ** self._exponent
73        c = -1j * z_phase * np.sin(np.pi * self._exponent / 2) / 4
74        return value.LinearDict(
75            {
76                'III': global_phase * (1 - c),
77                'IIZ': global_phase * c,
78                'IZI': global_phase * c,
79                'ZII': global_phase * c,
80                'ZZI': global_phase * -c,
81                'ZIZ': global_phase * -c,
82                'IZZ': global_phase * -c,
83                'ZZZ': global_phase * c,
84            }
85        )
86
87    def _decompose_(self, qubits):
88        """An adjacency-respecting decomposition.
89
90        0: ───p───@──────────────@───────@──────────@──────────
91                  │              │       │          │
92        1: ───p───X───@───p^-1───X───@───X──────@───X──────@───
93                      │              │          │          │
94        2: ───p───────X───p──────────X───p^-1───X───p^-1───X───
95
96        where p = T**self._exponent
97        """
98        if protocols.is_parameterized(self):
99            return NotImplemented
100
101        a, b, c = qubits
102
103        # Hacky magic: avoid the non-adjacent edge.
104        if hasattr(b, 'is_adjacent'):
105            if not b.is_adjacent(a):
106                b, c = c, b
107            elif not b.is_adjacent(c):
108                a, b = b, a
109
110        p = common_gates.T ** self._exponent
111        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]
112
113        return [
114            p(a),
115            p(b),
116            p(c),
117            sweep_abc,
118            p(b) ** -1,
119            p(c),
120            sweep_abc,
121            p(c) ** -1,
122            sweep_abc,
123            p(c) ** -1,
124            sweep_abc,
125        ]
126
127    def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
128        if protocols.is_parameterized(self):
129            return NotImplemented
130        ooo = args.subspace_index(0b111)
131        args.target_tensor[ooo] *= np.exp(1j * self.exponent * np.pi)
132        p = 1j ** (2 * self._exponent * self._global_shift)
133        if p != 1:
134            args.target_tensor *= p
135        return args.target_tensor
136
137    def _circuit_diagram_info_(
138        self, args: 'cirq.CircuitDiagramInfoArgs'
139    ) -> 'cirq.CircuitDiagramInfo':
140        return protocols.CircuitDiagramInfo(('@', '@', '@'), exponent=self._diagram_exponent(args))
141
142    def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
143        if self._exponent != 1:
144            return None
145
146        args.validate_version('2.0')
147        lines = [
148            args.format('h {0};\n', qubits[2]),
149            args.format('ccx {0},{1},{2};\n', qubits[0], qubits[1], qubits[2]),
150            args.format('h {0};\n', qubits[2]),
151        ]
152        return ''.join(lines)
153
154    def _quil_(
155        self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'
156    ) -> Optional[str]:
157        if self._exponent != 1:
158            return None
159        lines = [
160            formatter.format('H {0}\n', qubits[2]),
161            formatter.format('CCNOT {0} {1} {2}\n', qubits[0], qubits[1], qubits[2]),
162            formatter.format('H {0}\n', qubits[2]),
163        ]
164        return ''.join(lines)
165
166    def __repr__(self) -> str:
167        if self._global_shift == 0:
168            if self._exponent == 1:
169                return 'cirq.CCZ'
170            return f'(cirq.CCZ**{proper_repr(self._exponent)})'
171        return 'cirq.CCZPowGate(exponent={}, global_shift={!r})'.format(
172            proper_repr(self._exponent), self._global_shift
173        )
174
175    def __str__(self) -> str:
176        if self._exponent == 1:
177            return 'CCZ'
178        return f'CCZ**{self._exponent}'
179
180    def _num_qubits_(self) -> int:
181        return 3
182
183    def controlled(
184        self,
185        num_controls: int = None,
186        control_values: Optional[Sequence[Union[int, Collection[int]]]] = None,
187        control_qid_shape: Optional[Tuple[int, ...]] = None,
188    ) -> raw_types.Gate:
189        """Returns a controlled `ZPowGate` with two additional controls.
190
191        The `controlled` method of the `Gate` class, of which this class is a
192        child, returns a `ControlledGate` with `sub_gate = self`. This method
193        overrides this behavior to return a `ControlledGate` with
194        `sub_gate = ZPowGate`.
195        """
196        if num_controls == 0:
197            return self
198        return controlled_gate.ControlledGate(
199            controlled_gate.ControlledGate(
200                common_gates.ZPowGate(exponent=self._exponent, global_shift=self._global_shift),
201                num_controls=2,
202            ),
203            num_controls=num_controls,
204            control_values=control_values,
205            control_qid_shape=control_qid_shape,
206        )
207
208
209@value.value_equality()
210class ThreeQubitDiagonalGate(raw_types.Gate):
211    """A gate given by a diagonal 8x8 matrix."""
212
213    def __init__(self, diag_angles_radians: List[value.TParamVal]) -> None:
214        r"""A three qubit gate with only diagonal elements.
215
216        This gate's off-diagonal elements are zero and it's on diagonal
217        elements are all phases.
218
219        Args:
220            diag_angles_radians: The list of angles on the diagonal in radians.
221                If these values are $(x_0, x_1, \ldots , x_7)$ then the unitary
222                has diagonal values $(e^{i x_0}, e^{i x_1}, \ldots, e^{i x_7})$.
223        """
224        self._diag_angles_radians: List[value.TParamVal] = diag_angles_radians
225
226    def _is_parameterized_(self) -> bool:
227        return any(protocols.is_parameterized(angle) for angle in self._diag_angles_radians)
228
229    def _parameter_names_(self) -> AbstractSet[str]:
230        return {
231            name for angle in self._diag_angles_radians for name in protocols.parameter_names(angle)
232        }
233
234    def _resolve_parameters_(
235        self, resolver: 'cirq.ParamResolver', recursive: bool
236    ) -> 'ThreeQubitDiagonalGate':
237        return self.__class__(
238            [
239                protocols.resolve_parameters(angle, resolver, recursive)
240                for angle in self._diag_angles_radians
241            ]
242        )
243
244    def _has_unitary_(self) -> bool:
245        return not self._is_parameterized_()
246
247    def _unitary_(self) -> np.ndarray:
248        if self._is_parameterized_():
249            return NotImplemented
250        return np.diag([np.exp(1j * angle) for angle in self._diag_angles_radians])
251
252    def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
253        if self._is_parameterized_():
254            return NotImplemented
255        for index, angle in enumerate(self._diag_angles_radians):
256            little_endian_index = 4 * (index & 1) + 2 * ((index >> 1) & 1) + ((index >> 2) & 1)
257            subspace_index = args.subspace_index(little_endian_index)
258            args.target_tensor[subspace_index] *= np.exp(1j * angle)
259        return args.target_tensor
260
261    def _circuit_diagram_info_(
262        self, args: 'cirq.CircuitDiagramInfoArgs'
263    ) -> 'cirq.CircuitDiagramInfo':
264        rounded_angles = np.array(self._diag_angles_radians)
265        if args.precision is not None:
266            rounded_angles = rounded_angles.round(args.precision)
267        diag_str = f"diag({', '.join(proper_repr(angle) for angle in rounded_angles)})"
268        return protocols.CircuitDiagramInfo((diag_str, '#2', '#3'))
269
270    def __pow__(self, exponent: Any) -> 'ThreeQubitDiagonalGate':
271        if not isinstance(exponent, (int, float, sympy.Basic)):
272            return NotImplemented
273        return ThreeQubitDiagonalGate(
274            [protocols.mul(angle, exponent, NotImplemented) for angle in self._diag_angles_radians]
275        )
276
277    def _decompose_(self, qubits):
278        """An adjacency-respecting decomposition.
279
280        0: ───p_0───@──────────────@───────@──────────@──────────
281                    │              │       │          │
282        1: ───p_1───X───@───p_3────X───@───X──────@───X──────@───
283                        │              │          │          │
284        2: ───p_2───────X───p_4────────X───p_5────X───p_6────X───
285
286        where p_i = T**(4*x_i) and x_i solve the system of equations
287                    [0, 0, 1, 0, 1, 1, 1][x_0]   [r_1]
288                    [0, 1, 0, 1, 1, 0, 1][x_1]   [r_2]
289                    [0, 1, 1, 1, 0, 1, 0][x_2]   [r_3]
290                    [1, 0, 0, 1, 1, 1, 0][x_3] = [r_4]
291                    [1, 0, 1, 1, 0, 0, 1][x_4]   [r_5]
292                    [1, 1, 0, 0, 0, 1, 1][x_5]   [r_6]
293                    [1, 1, 1, 0, 1, 0, 0][x_6]   [r_7]
294        where r_i is self._diag_angles_radians[i].
295
296        The above system was created by equating the composition of the gates
297        in the circuit diagram to np.diag(self._diag_angles) (shifted by a
298        global phase of np.exp(-1j * self._diag_angles[0])).
299        """
300
301        a, b, c = qubits
302        if hasattr(b, 'is_adjacent'):
303            if not b.is_adjacent(a):
304                b, c = c, b
305            elif not b.is_adjacent(c):
306                a, b = b, a
307        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]
308        phase_matrix_inverse = 0.25 * np.array(
309            [
310                [-1, -1, -1, 1, 1, 1, 1],
311                [-1, 1, 1, -1, -1, 1, 1],
312                [1, -1, 1, -1, 1, -1, 1],
313                [-1, 1, 1, 1, 1, -1, -1],
314                [1, 1, -1, 1, -1, -1, 1],
315                [1, -1, 1, 1, -1, 1, -1],
316                [1, 1, -1, -1, 1, 1, -1],
317            ]
318        )
319        shifted_angles_tail = [
320            angle - self._diag_angles_radians[0] for angle in self._diag_angles_radians[1:]
321        ]
322        phase_solutions = phase_matrix_inverse.dot(shifted_angles_tail)
323        p_gates = [pauli_gates.Z ** (solution / np.pi) for solution in phase_solutions]
324
325        return [
326            p_gates[0](a),
327            p_gates[1](b),
328            p_gates[2](c),
329            sweep_abc,
330            p_gates[3](b),
331            p_gates[4](c),
332            sweep_abc,
333            p_gates[5](c),
334            sweep_abc,
335            p_gates[6](c),
336            sweep_abc,
337        ]
338
339    def _value_equality_values_(self):
340        return tuple(self._diag_angles_radians)
341
342    def _pauli_expansion_(self) -> value.LinearDict[str]:
343        if protocols.is_parameterized(self):
344            return NotImplemented
345        x = [np.exp(1j * angle) for angle in self._diag_angles_radians]
346        return value.LinearDict(
347            {
348                'III': (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + x[7]) / 8,
349                'IIZ': (x[0] - x[1] + x[2] - x[3] + x[4] - x[5] + x[6] - x[7]) / 8,
350                'IZI': (x[0] + x[1] - x[2] - x[3] + x[4] + x[5] - x[6] - x[7]) / 8,
351                'IZZ': (x[0] - x[1] - x[2] + x[3] + x[4] - x[5] - x[6] + x[7]) / 8,
352                'ZII': (x[0] + x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7]) / 8,
353                'ZIZ': (x[0] - x[1] + x[2] - x[3] - x[4] + x[5] - x[6] + x[7]) / 8,
354                'ZZI': (x[0] + x[1] - x[2] - x[3] - x[4] - x[5] + x[6] + x[7]) / 8,
355                'ZZZ': (x[0] - x[1] - x[2] + x[3] - x[4] + x[5] + x[6] - x[7]) / 8,
356            }
357        )
358
359    def __repr__(self) -> str:
360        return 'cirq.ThreeQubitDiagonalGate([{}])'.format(
361            ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
362        )
363
364    def _num_qubits_(self) -> int:
365        return 3
366
367
368class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
369    """A Toffoli (doubly-controlled-NOT) that can be raised to a power.
370
371    The matrix of `CCX**t` is an 8x8 identity except the bottom right 2x2 area
372    is the matrix of `X**t`.
373    """
374
375    def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
376        return [
377            (0, linalg.block_diag(np.diag([1, 1, 1, 1, 1, 1]), np.array([[0.5, 0.5], [0.5, 0.5]]))),
378            (
379                1,
380                linalg.block_diag(
381                    np.diag([0, 0, 0, 0, 0, 0]), np.array([[0.5, -0.5], [-0.5, 0.5]])
382                ),
383            ),
384        ]
385
386    def _trace_distance_bound_(self) -> Optional[float]:
387        if self._is_parameterized_():
388            return None
389        return abs(np.sin(self._exponent * 0.5 * np.pi))
390
391    def _pauli_expansion_(self) -> value.LinearDict[str]:
392        if protocols.is_parameterized(self):
393            return NotImplemented
394        global_phase = 1j ** (2 * self._exponent * self._global_shift)
395        z_phase = 1j ** self._exponent
396        c = -1j * z_phase * np.sin(np.pi * self._exponent / 2) / 4
397        return value.LinearDict(
398            {
399                'III': global_phase * (1 - c),
400                'IIX': global_phase * c,
401                'IZI': global_phase * c,
402                'ZII': global_phase * c,
403                'ZZI': global_phase * -c,
404                'ZIX': global_phase * -c,
405                'IZX': global_phase * -c,
406                'ZZX': global_phase * c,
407            }
408        )
409
410    def qubit_index_to_equivalence_group_key(self, index):
411        return index < 2
412
413    def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
414        if protocols.is_parameterized(self):
415            return NotImplemented
416        p = 1j ** (2 * self._exponent * self._global_shift)
417        if p != 1:
418            args.target_tensor *= p
419        return protocols.apply_unitary(
420            controlled_gate.ControlledGate(
421                controlled_gate.ControlledGate(pauli_gates.X ** self.exponent)
422            ),
423            protocols.ApplyUnitaryArgs(args.target_tensor, args.available_buffer, args.axes),
424            default=NotImplemented,
425        )
426
427    def _decompose_(self, qubits):
428        c1, c2, t = qubits
429        yield common_gates.H(t)
430        yield CCZ(c1, c2, t) ** self._exponent
431        yield common_gates.H(t)
432
433    def _circuit_diagram_info_(
434        self, args: 'cirq.CircuitDiagramInfoArgs'
435    ) -> 'cirq.CircuitDiagramInfo':
436        return protocols.CircuitDiagramInfo(
437            ('@', '@', 'X'), exponent=self._diagram_exponent(args), exponent_qubit_index=2
438        )
439
440    def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
441        if self._exponent != 1:
442            return None
443
444        args.validate_version('2.0')
445        return args.format('ccx {0},{1},{2};\n', qubits[0], qubits[1], qubits[2])
446
447    def _quil_(
448        self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'
449    ) -> Optional[str]:
450        if self._exponent != 1:
451            return None
452        return formatter.format('CCNOT {0} {1} {2}\n', qubits[0], qubits[1], qubits[2])
453
454    def __repr__(self) -> str:
455        if self._global_shift == 0:
456            if self._exponent == 1:
457                return 'cirq.TOFFOLI'
458            return f'(cirq.TOFFOLI**{proper_repr(self._exponent)})'
459        return 'cirq.CCXPowGate(exponent={}, global_shift={!r})'.format(
460            proper_repr(self._exponent), self._global_shift
461        )
462
463    def __str__(self) -> str:
464        if self._exponent == 1:
465            return 'TOFFOLI'
466        return f'TOFFOLI**{self._exponent}'
467
468    def _num_qubits_(self) -> int:
469        return 3
470
471    def controlled(
472        self,
473        num_controls: int = None,
474        control_values: Optional[Sequence[Union[int, Collection[int]]]] = None,
475        control_qid_shape: Optional[Tuple[int, ...]] = None,
476    ) -> raw_types.Gate:
477        """Returns a controlled `XPowGate` with two additional controls.
478
479        The `controlled` method of the `Gate` class, of which this class is a
480        child, returns a `ControlledGate` with `sub_gate = self`. This method
481        overrides this behavior to return a `ControlledGate` with
482        `sub_gate = XPowGate`.
483        """
484        if num_controls == 0:
485            return self
486        return controlled_gate.ControlledGate(
487            controlled_gate.ControlledGate(
488                common_gates.XPowGate(exponent=self._exponent, global_shift=self._global_shift),
489                num_controls=2,
490            ),
491            num_controls=num_controls,
492            control_values=control_values,
493            control_qid_shape=control_qid_shape,
494        )
495
496
497@value.value_equality()
498class CSwapGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
499    """A controlled swap gate. The Fredkin gate."""
500
501    def qubit_index_to_equivalence_group_key(self, index):
502        return 0 if index == 0 else 1
503
504    def _pauli_expansion_(self) -> value.LinearDict[str]:
505        return value.LinearDict(
506            {
507                'III': 3 / 4,
508                'IXX': 1 / 4,
509                'IYY': 1 / 4,
510                'IZZ': 1 / 4,
511                'ZII': 1 / 4,
512                'ZXX': -1 / 4,
513                'ZYY': -1 / 4,
514                'ZZZ': -1 / 4,
515            }
516        )
517
518    def _trace_distance_bound_(self) -> float:
519        return 1.0
520
521    def _decompose_(self, qubits):
522        c, t1, t2 = qubits
523
524        # Hacky magic: special case based on adjacency.
525        if hasattr(t1, 'is_adjacent'):
526            if not t1.is_adjacent(t2):
527                # Targets separated by control.
528                return self._decompose_inside_control(t1, c, t2)
529            if not t1.is_adjacent(c):
530                # Control separated from t1 by t2.
531                return self._decompose_outside_control(c, t2, t1)
532
533        return self._decompose_outside_control(c, t1, t2)
534
535    def _decompose_inside_control(
536        self, target1: 'cirq.Qid', control: 'cirq.Qid', target2: 'cirq.Qid'
537    ) -> 'cirq.OP_TREE':
538        """A decomposition assuming the control separates the targets.
539
540        target1: ─@─X───────T──────@────────@─────────X───@─────X^-0.5─
541                  │ │              │        │         │   │
542        control: ─X─@─X─────@─T^-1─X─@─T────X─@─X^0.5─@─@─X─@──────────
543                      │     │        │        │         │   │
544        target2: ─────@─H─T─X─T──────X─T^-1───X─T^-1────X───X─H─S^-1───
545        """
546        a, b, c = target1, control, target2
547        yield common_gates.CNOT(a, b)
548        yield common_gates.CNOT(b, a)
549        yield common_gates.CNOT(c, b)
550        yield common_gates.H(c)
551        yield common_gates.T(c)
552        yield common_gates.CNOT(b, c)
553        yield common_gates.T(a)
554        yield common_gates.T(b) ** -1
555        yield common_gates.T(c)
556        yield common_gates.CNOT(a, b)
557        yield common_gates.CNOT(b, c)
558        yield common_gates.T(b)
559        yield common_gates.T(c) ** -1
560        yield common_gates.CNOT(a, b)
561        yield common_gates.CNOT(b, c)
562        yield pauli_gates.X(b) ** 0.5
563        yield common_gates.T(c) ** -1
564        yield common_gates.CNOT(b, a)
565        yield common_gates.CNOT(b, c)
566        yield common_gates.CNOT(a, b)
567        yield common_gates.CNOT(b, c)
568        yield common_gates.H(c)
569        yield common_gates.S(c) ** -1
570        yield pauli_gates.X(a) ** -0.5
571
572    def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
573        return protocols.apply_unitary(
574            controlled_gate.ControlledGate(swap_gates.SWAP),
575            protocols.ApplyUnitaryArgs(args.target_tensor, args.available_buffer, args.axes),
576            default=NotImplemented,
577        )
578
579    def _decompose_outside_control(
580        self, control: 'cirq.Qid', near_target: 'cirq.Qid', far_target: 'cirq.Qid'
581    ) -> 'cirq.OP_TREE':
582        """A decomposition assuming one of the targets is in the middle.
583
584        control: ───T──────@────────@───@────────────@────────────────
585                           │        │   │            │
586           near: ─X─T──────X─@─T^-1─X─@─X────@─X^0.5─X─@─X^0.5────────
587                  │          │        │      │         │
588            far: ─@─Y^-0.5─T─X─T──────X─T^-1─X─T^-1────X─S─────X^-0.5─
589        """
590        a, b, c = control, near_target, far_target
591
592        t = common_gates.T
593        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]
594
595        yield common_gates.CNOT(c, b)
596        yield pauli_gates.Y(c) ** -0.5
597        yield t(a), t(b), t(c)
598        yield sweep_abc
599        yield t(b) ** -1, t(c)
600        yield sweep_abc
601        yield t(c) ** -1
602        yield sweep_abc
603        yield t(c) ** -1
604        yield pauli_gates.X(b) ** 0.5
605        yield sweep_abc
606        yield common_gates.S(c)
607        yield pauli_gates.X(b) ** 0.5
608        yield pauli_gates.X(c) ** -0.5
609
610    def _has_unitary_(self) -> bool:
611        return True
612
613    def _unitary_(self) -> np.ndarray:
614        return linalg.block_diag(np.diag([1, 1, 1, 1, 1]), np.array([[0, 1], [1, 0]]), np.diag([1]))
615
616    def _circuit_diagram_info_(
617        self, args: 'cirq.CircuitDiagramInfoArgs'
618    ) -> 'cirq.CircuitDiagramInfo':
619        if not args.use_unicode_characters:
620            return protocols.CircuitDiagramInfo(('@', 'swap', 'swap'))
621        return protocols.CircuitDiagramInfo(('@', '×', '×'))
622
623    def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
624        args.validate_version('2.0')
625        return args.format('cswap {0},{1},{2};\n', qubits[0], qubits[1], qubits[2])
626
627    def _quil_(
628        self, qubits: Tuple['cirq.Qid', ...], formatter: 'cirq.QuilFormatter'
629    ) -> Optional[str]:
630        return formatter.format('CSWAP {0} {1} {2}\n', qubits[0], qubits[1], qubits[2])
631
632    def _value_equality_values_(self):
633        return ()
634
635    def __str__(self) -> str:
636        return 'FREDKIN'
637
638    def __repr__(self) -> str:
639        return 'cirq.FREDKIN'
640
641    def _num_qubits_(self) -> int:
642        return 3
643
644    def controlled(
645        self,
646        num_controls: int = None,
647        control_values: Optional[Sequence[Union[int, Collection[int]]]] = None,
648        control_qid_shape: Optional[Tuple[int, ...]] = None,
649    ) -> raw_types.Gate:
650        """Returns a controlled `SWAP` with one additional control.
651
652        The `controlled` method of the `Gate` class, of which this class is a
653        child, returns a `ControlledGate` with `sub_gate = self`. This method
654        overrides this behavior to return a `ControlledGate` with
655        `sub_gate = SWAP`.
656        """
657        if num_controls == 0:
658            return self
659        return controlled_gate.ControlledGate(
660            controlled_gate.ControlledGate(swap_gates.SWAP, num_controls=1),
661            num_controls=num_controls,
662            control_values=control_values,
663            control_qid_shape=control_qid_shape,
664        )
665
666
667CCZ = CCZPowGate()
668document(
669    CCZ,
670    """The Controlled-Controlled-Z gate.
671
672    The `exponent=1` instance of `cirq.CCZPowGate`.
673
674    Matrix:
675
676    ```
677        [[1 . . . . . . .],
678         [. 1 . . . . . .],
679         [. . 1 . . . . .],
680         [. . . 1 . . . .],
681         [. . . . 1 . . .],
682         [. . . . . 1 . .],
683         [. . . . . . 1 .],
684         [. . . . . . . -1]]
685    ```
686    """,
687)
688
689CCNotPowGate = CCXPowGate
690CCX = TOFFOLI = CCNOT = CCXPowGate()
691document(
692    CCX,
693    """The TOFFOLI gate, also known as the Controlled-Controlled-X gate.
694
695    If the first two qubits are in the |11⟩ state, this flips the third qubit
696    in the computational basis, otherwise this applies identity to the third qubit.
697
698    The `exponent=1` instance of `cirq.CCXPowGate`.
699
700    Matrix:
701    ```
702        [[1 . . . . . . .],
703         [. 1 . . . . . .],
704         [. . 1 . . . . .],
705         [. . . 1 . . . .],
706         [. . . . 1 . . .],
707         [. . . . . 1 . .],
708         [. . . . . . . 1],
709         [. . . . . . 1 .]]
710    ```
711    """,
712)
713
714CSWAP = FREDKIN = CSwapGate()
715document(
716    CSWAP,
717    """The Controlled Swap gate, also known as the Fredkin gate.
718
719    If the first qubit is |1⟩, this applies a SWAP between the second and third qubit,
720    otherwise it acts as identity on the second and third qubit.
721
722    An instance of `cirq.CSwapGate`.
723
724    Matrix:
725    ```
726        [[1 . . . . . . .],
727         [. 1 . . . . . .],
728         [. . 1 . . . . .],
729         [. . . 1 . . . .],
730         [. . . . 1 . . .],
731         [. . . . . . 1 .],
732         [. . . . . 1 . .],
733         [. . . . . . . 1]]
734    ```
735    """,
736)
737