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