Coverage for src/braket/circuits/gates.py : 99%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"). You
4# may not use this file except in compliance with the License. A copy of
5# the License is located at
6#
7# http://aws.amazon.com/apache2.0/
8#
9# or in the "license" file accompanying this file. This file is
10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11# ANY KIND, either express or implied. See the License for the specific
12# language governing permissions and limitations under the License.
14import math
15from typing import Iterable
17import braket.ir.jaqcd as ir
18import numpy as np
19from braket.circuits import circuit
20from braket.circuits.angled_gate import AngledGate
21from braket.circuits.gate import Gate
22from braket.circuits.instruction import Instruction
23from braket.circuits.qubit import QubitInput
24from braket.circuits.qubit_set import QubitSet, QubitSetInput
26# TODO: look into adding angle to diagrams
28"""
29To add a new gate:
30 1. Implement the class and extend `Gate`
31 2. Add a method with the `@circuit.subroutine(register=True)` decorator. Method name
32 will be added into the `Circuit` class. This method is the default way
33 clients add this gate to a circuit.
34 3. Register the class with the `Gate` class via `Gate.register_gate()`.
35"""
37# Single qubit gates #
40class H(Gate):
41 """Hadamard gate."""
43 def __init__(self):
44 super().__init__(qubit_count=1, ascii_symbols=["H"])
46 def to_ir(self, target: QubitSet):
47 return ir.H(target=target[0])
49 def to_matrix(self) -> np.ndarray:
50 return 1.0 / np.sqrt(2.0) * np.array([[1.0, 1.0], [1.0, -1.0]], dtype=complex)
52 @staticmethod
53 @circuit.subroutine(register=True)
54 def h(target: QubitSetInput) -> Iterable[Instruction]:
55 """Registers this function into the circuit class.
57 Args:
58 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
60 Returns:
61 Iterable[Instruction]: `Iterable` of H instructions.
63 Examples:
64 >>> circ = Circuit().h(0)
65 >>> circ = Circuit().h([0, 1, 2])
66 """
67 return [Instruction(Gate.H(), target=qubit) for qubit in QubitSet(target)]
70Gate.register_gate(H)
73class I(Gate): # noqa: E742, E261
74 """Identity gate."""
76 def __init__(self):
77 super().__init__(qubit_count=1, ascii_symbols=["I"])
79 def to_ir(self, target: QubitSet):
80 return ir.I(target=target[0])
82 def to_matrix(self) -> np.ndarray:
83 return np.array([[1.0, 0.0], [0.0, 1.0]], dtype=complex)
85 @staticmethod
86 @circuit.subroutine(register=True)
87 def i(target: QubitSetInput) -> Iterable[Instruction]:
88 """Registers this function into the circuit class.
90 Args:
91 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
93 Returns:
94 Iterable[Instruction]: `Iterable` of I instructions.
96 Examples:
97 >>> circ = Circuit().i(0)
98 >>> circ = Circuit().i([0, 1, 2])
99 """
100 return [Instruction(Gate.I(), target=qubit) for qubit in QubitSet(target)]
103Gate.register_gate(I)
106class X(Gate):
107 """Pauli-X gate."""
109 def __init__(self):
110 super().__init__(qubit_count=1, ascii_symbols=["X"])
112 def to_ir(self, target: QubitSet):
113 return ir.X(target=target[0])
115 def to_matrix(self) -> np.ndarray:
116 return np.array([[0.0, 1.0], [1.0, 0.0]], dtype=complex)
118 @staticmethod
119 @circuit.subroutine(register=True)
120 def x(target: QubitSetInput) -> Iterable[Instruction]:
121 """Registers this function into the circuit class.
123 Args:
124 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
126 Returns:
127 Iterable[Instruction]: `Iterable` of X instructions.
129 Examples:
130 >>> circ = Circuit().x(0)
131 >>> circ = Circuit().x([0, 1, 2])
132 """
133 return [Instruction(Gate.X(), target=qubit) for qubit in QubitSet(target)]
136Gate.register_gate(X)
139class Y(Gate):
140 """Pauli-Y gate."""
142 def __init__(self):
143 super().__init__(qubit_count=1, ascii_symbols=["Y"])
145 def to_ir(self, target: QubitSet):
146 return ir.Y(target=target[0])
148 def to_matrix(self) -> np.ndarray:
149 return np.array([[0.0, -1.0j], [1.0j, 0.0]], dtype=complex)
151 @staticmethod
152 @circuit.subroutine(register=True)
153 def y(target: QubitSetInput) -> Iterable[Instruction]:
154 """Registers this function into the circuit class.
156 Args:
157 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
159 Returns:
160 Iterable[Instruction]: `Iterable` of Y instructions.
162 Examples:
163 >>> circ = Circuit().y(0)
164 >>> circ = Circuit().y([0, 1, 2])
165 """
166 return [Instruction(Gate.Y(), target=qubit) for qubit in QubitSet(target)]
169Gate.register_gate(Y)
172class Z(Gate):
173 """Pauli-Z gate."""
175 def __init__(self):
176 super().__init__(qubit_count=1, ascii_symbols=["Z"])
178 def to_ir(self, target: QubitSet):
179 return ir.Z(target=target[0])
181 def to_matrix(self) -> np.ndarray:
182 return np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex)
184 @staticmethod
185 @circuit.subroutine(register=True)
186 def z(target: QubitSetInput) -> Iterable[Instruction]:
187 """Registers this function into the circuit class.
189 Args:
190 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
192 Returns:
193 Iterable[Instruction]: `Iterable` of Z instructions.
195 Examples:
196 >>> circ = Circuit().z(0)
197 >>> circ = Circuit().z([0, 1, 2])
198 """
199 return [Instruction(Gate.Z(), target=qubit) for qubit in QubitSet(target)]
202Gate.register_gate(Z)
205class S(Gate):
206 """S gate."""
208 def __init__(self):
209 super().__init__(qubit_count=1, ascii_symbols=["S"])
211 def to_ir(self, target: QubitSet):
212 return ir.S(target=target[0])
214 def to_matrix(self) -> np.ndarray:
216 return np.array([[1.0, 0.0], [0.0, 1.0j]], dtype=complex)
218 @staticmethod
219 @circuit.subroutine(register=True)
220 def s(target: QubitSetInput) -> Iterable[Instruction]:
221 """Registers this function into the circuit class.
223 Args:
224 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
226 Returns:
227 Iterable[Instruction]: `Iterable` of S instructions.
229 Examples:
230 >>> circ = Circuit().s(0)
231 >>> circ = Circuit().s([0, 1, 2])
232 """
233 return [Instruction(Gate.S(), target=qubit) for qubit in QubitSet(target)]
236Gate.register_gate(S)
239class Si(Gate):
240 """Conjugate transpose of S gate."""
242 def __init__(self):
243 super().__init__(qubit_count=1, ascii_symbols=["Si"])
245 def to_ir(self, target: QubitSet):
246 return ir.Si(target=target[0])
248 def to_matrix(self) -> np.ndarray:
249 return np.array([[1, 0], [0, -1j]], dtype=complex)
251 @staticmethod
252 @circuit.subroutine(register=True)
253 def si(target: QubitSetInput) -> Iterable[Instruction]:
254 """Registers this function into the circuit class.
256 Args:
257 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
259 Returns:
260 Iterable[Instruction]: Iterable of Si instructions.
262 Examples:
263 >>> circ = Circuit().si(0)
264 >>> circ = Circuit().si([0, 1, 2])
265 """
266 return [Instruction(Gate.Si(), target=qubit) for qubit in QubitSet(target)]
269Gate.register_gate(Si)
272class T(Gate):
273 """T gate."""
275 def __init__(self):
276 super().__init__(qubit_count=1, ascii_symbols=["T"])
278 def to_ir(self, target: QubitSet):
279 return ir.T(target=target[0])
281 def to_matrix(self) -> np.ndarray:
282 return np.array([[1.0, 0.0], [0.0, np.exp(1j * np.pi / 4)]], dtype=complex)
284 @staticmethod
285 @circuit.subroutine(register=True)
286 def t(target: QubitSetInput) -> Iterable[Instruction]:
287 """Registers this function into the circuit class.
289 Args:
290 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
292 Returns:
293 Iterable[Instruction]: `Iterable` of T instructions.
295 Examples:
296 >>> circ = Circuit().t(0)
297 >>> circ = Circuit().t([0, 1, 2])
298 """
299 return [Instruction(Gate.T(), target=qubit) for qubit in QubitSet(target)]
302Gate.register_gate(T)
305class Ti(Gate):
306 """Conjugate transpose of T gate."""
308 def __init__(self):
309 super().__init__(qubit_count=1, ascii_symbols=["Ti"])
311 def to_ir(self, target: QubitSet):
312 return ir.Ti(target=target[0])
314 def to_matrix(self) -> np.ndarray:
315 return np.array([[1.0, 0.0], [0.0, np.exp(-1j * np.pi / 4)]], dtype=complex)
317 @staticmethod
318 @circuit.subroutine(register=True)
319 def ti(target: QubitSetInput) -> Iterable[Instruction]:
320 """Registers this function into the circuit class.
322 Args:
323 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
325 Returns:
326 Iterable[Instruction]: `Iterable` of Ti instructions.
328 Examples:
329 >>> circ = Circuit().ti(0)
330 >>> circ = Circuit().ti([0, 1, 2])
331 """
332 return [Instruction(Gate.Ti(), target=qubit) for qubit in QubitSet(target)]
335Gate.register_gate(Ti)
338class V(Gate):
339 """Square root of not gate."""
341 def __init__(self):
342 super().__init__(qubit_count=1, ascii_symbols=["V"])
344 def to_ir(self, target: QubitSet):
345 return ir.V(target=target[0])
347 def to_matrix(self) -> np.ndarray:
348 return np.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=complex)
350 @staticmethod
351 @circuit.subroutine(register=True)
352 def v(target: QubitSetInput) -> Iterable[Instruction]:
353 """Registers this function into the circuit class.
355 Args:
356 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
358 Returns:
359 Iterable[Instruction]: `Iterable` of V instructions.
361 Examples:
362 >>> circ = Circuit().v(0)
363 >>> circ = Circuit().v([0, 1, 2])
364 """
365 return [Instruction(Gate.V(), target=qubit) for qubit in QubitSet(target)]
368Gate.register_gate(V)
371class Vi(Gate):
372 """Conjugate transpose of square root of not gate."""
374 def __init__(self):
375 super().__init__(qubit_count=1, ascii_symbols=["Vi"])
377 def to_ir(self, target: QubitSet):
378 return ir.Vi(target=target[0])
380 def to_matrix(self) -> np.ndarray:
381 return np.array(([[0.5 - 0.5j, 0.5 + 0.5j], [0.5 + 0.5j, 0.5 - 0.5j]]), dtype=complex)
383 @staticmethod
384 @circuit.subroutine(register=True)
385 def vi(target: QubitSetInput) -> Iterable[Instruction]:
386 """Registers this function into the circuit class.
388 Args:
389 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
391 Returns:
392 Iterable[Instruction]: `Iterable` of Vi instructions.
394 Examples:
395 >>> circ = Circuit().vi(0)
396 >>> circ = Circuit().vi([0, 1, 2])
397 """
398 return [Instruction(Gate.Vi(), target=qubit) for qubit in QubitSet(target)]
401Gate.register_gate(Vi)
404# Single qubit gates with rotation #
407class Rx(AngledGate):
408 """X-axis rotation gate.
410 Args:
411 angle (float): angle in radians.
412 """
414 def __init__(self, angle: float):
415 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rx({:.3g})".format(angle)])
417 def to_ir(self, target: QubitSet):
418 return ir.Rx(target=target[0], angle=self.angle)
420 def to_matrix(self) -> np.ndarray:
421 cos = np.cos(self.angle / 2)
422 sin = np.sin(self.angle / 2)
423 return np.array([[cos, -1j * sin], [-1j * sin, cos]], dtype=complex)
425 @staticmethod
426 @circuit.subroutine(register=True)
427 def rx(target: QubitInput, angle: float) -> Instruction:
428 """Registers this function into the circuit class.
430 Args:
431 target (Qubit or int): Target qubit index.
432 angle (float): Angle in radians.
434 Returns:
435 Instruction: Rx instruction.
437 Examples:
438 >>> circ = Circuit().rx(0, 0.15)
439 """
440 return [Instruction(Gate.Rx(angle), target=qubit) for qubit in QubitSet(target)]
443Gate.register_gate(Rx)
446class Ry(AngledGate):
447 """Y-axis rotation gate.
449 Args:
450 angle (float): angle in radians.
451 """
453 def __init__(self, angle: float):
454 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Ry({:.3g})".format(angle)])
456 def to_ir(self, target: QubitSet):
457 return ir.Ry(target=target[0], angle=self.angle)
459 def to_matrix(self) -> np.ndarray:
460 cos = np.cos(self.angle / 2)
461 sin = np.sin(self.angle / 2)
462 return np.array([[cos, -sin], [+sin, cos]], dtype=complex)
464 @staticmethod
465 @circuit.subroutine(register=True)
466 def ry(target: QubitInput, angle: float) -> Instruction:
467 """Registers this function into the circuit class.
469 Args:
470 target (Qubit or int): Target qubit index.
471 angle (float): Angle in radians.
473 Returns:
474 Instruction: Ry instruction.
476 Examples:
477 >>> circ = Circuit().ry(0, 0.15)
478 """
479 return [Instruction(Gate.Ry(angle), target=qubit) for qubit in QubitSet(target)]
482Gate.register_gate(Ry)
485class Rz(AngledGate):
486 """Z-axis rotation gate.
488 Args:
489 angle (float): angle in radians.
490 """
492 def __init__(self, angle: float):
493 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rz({:.3g})".format(angle)])
495 def to_ir(self, target: QubitSet):
496 return ir.Rz(target=target[0], angle=self.angle)
498 def to_matrix(self) -> np.ndarray:
499 return np.array(
500 [[np.exp(-1j * self.angle / 2), 0], [0, np.exp(1j * self.angle / 2)]], dtype=complex
501 )
503 @staticmethod
504 @circuit.subroutine(register=True)
505 def rz(target: QubitInput, angle: float) -> Instruction:
506 """Registers this function into the circuit class.
508 Args:
509 target (Qubit or int): Target qubit index.
510 angle (float): Angle in radians.
512 Returns:
513 Instruction: Rz instruction.
515 Examples:
516 >>> circ = Circuit().rz(0, 0.15)
517 """
518 return [Instruction(Gate.Rz(angle), target=qubit) for qubit in QubitSet(target)]
521Gate.register_gate(Rz)
524class PhaseShift(AngledGate):
525 """Phase shift gate.
527 Args:
528 angle (float): angle in radians.
529 """
531 def __init__(self, angle: float):
532 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["PHASE({:.3g})".format(angle)])
534 def to_ir(self, target: QubitSet):
535 return ir.PhaseShift(target=target[0], angle=self.angle)
537 def to_matrix(self) -> np.ndarray:
538 return np.array([[1.0, 0.0], [0.0, np.exp(1j * self.angle)]], dtype=complex)
540 @staticmethod
541 @circuit.subroutine(register=True)
542 def phaseshift(target: QubitInput, angle: float) -> Instruction:
543 """Registers this function into the circuit class.
545 Args:
546 target (Qubit or int): Target qubit index.
547 angle (float): Angle in radians.
549 Returns:
550 Instruction: PhaseShift instruction.
552 Examples:
553 >>> circ = Circuit().phaseshift(0, 0.15)
554 """
555 return [Instruction(Gate.PhaseShift(angle), target=qubit) for qubit in QubitSet(target)]
558Gate.register_gate(PhaseShift)
561# Two qubit gates #
564class CNot(Gate):
565 """Controlled NOT gate."""
567 def __init__(self):
568 super().__init__(qubit_count=2, ascii_symbols=["C", "X"])
570 def to_ir(self, target: QubitSet):
571 return ir.CNot(control=target[0], target=target[1])
573 def to_matrix(self) -> np.ndarray:
574 return np.array(
575 [
576 [1.0, 0.0, 0.0, 0.0],
577 [0.0, 1.0, 0.0, 0.0],
578 [0.0, 0.0, 0.0, 1.0],
579 [0.0, 0.0, 1.0, 0.0],
580 ],
581 dtype=complex,
582 )
584 @staticmethod
585 @circuit.subroutine(register=True)
586 def cnot(control: QubitInput, target: QubitInput) -> Instruction:
587 """Registers this function into the circuit class.
589 Args:
590 control (Qubit or int): Control qubit index.
591 target (Qubit or int): Target qubit index.
593 Returns:
594 Instruction: CNot instruction.
596 Examples:
597 >>> circ = Circuit().cnot(0, 1)
598 """
599 return Instruction(Gate.CNot(), target=[control, target])
602Gate.register_gate(CNot)
605class Swap(Gate):
606 """Swap gate."""
608 def __init__(self):
609 super().__init__(qubit_count=2, ascii_symbols=["SWAP", "SWAP"])
611 def to_ir(self, target: QubitSet):
612 return ir.Swap(targets=[target[0], target[1]])
614 def to_matrix(self) -> np.ndarray:
615 return np.array(
616 [
617 [1.0, 0.0, 0.0, 0.0],
618 [0.0, 0.0, 1.0, 0.0],
619 [0.0, 1.0, 0.0, 0.0],
620 [0.0, 0.0, 0.0, 1.0],
621 ],
622 dtype=complex,
623 )
625 @staticmethod
626 @circuit.subroutine(register=True)
627 def swap(target1: QubitInput, target2: QubitInput) -> Instruction:
628 """Registers this function into the circuit class.
630 Args:
631 target1 (Qubit or int): Target qubit 1 index.
632 target2 (Qubit or int): Target qubit 2 index.
634 Returns:
635 Instruction: Swap instruction.
637 Examples:
638 >>> circ = Circuit().swap(0, 1)
639 """
640 return Instruction(Gate.Swap(), target=[target1, target2])
643Gate.register_gate(Swap)
646class ISwap(Gate):
647 """ISwap gate."""
649 def __init__(self):
650 super().__init__(qubit_count=2, ascii_symbols=["ISWAP", "ISWAP"])
652 def to_ir(self, target: QubitSet):
653 return ir.ISwap(targets=[target[0], target[1]])
655 def to_matrix(self) -> np.ndarray:
656 return np.array(
657 [
658 [1.0, 0.0, 0.0, 0.0],
659 [0.0, 0.0, 1.0j, 0.0],
660 [0.0, 1.0j, 0.0, 0.0],
661 [0.0, 0.0, 0.0, 1.0],
662 ],
663 dtype=complex,
664 )
666 @staticmethod
667 @circuit.subroutine(register=True)
668 def iswap(target1: QubitInput, target2: QubitInput) -> Instruction:
669 """Registers this function into the circuit class.
671 Args:
672 target1 (Qubit or int): Target qubit 1 index.
673 target2 (Qubit or int): Target qubit 2 index.
675 Returns:
676 Instruction: ISwap instruction.
678 Examples:
679 >>> circ = Circuit().iswap(0, 1)
680 """
681 return Instruction(Gate.ISwap(), target=[target1, target2])
684Gate.register_gate(ISwap)
687class PSwap(AngledGate):
688 """PSwap gate.
690 Args:
691 angle (float): angle in radians.
692 """
694 def __init__(self, angle: float):
695 super().__init__(
696 angle=angle,
697 qubit_count=2,
698 ascii_symbols=["PSWAP({:.3g})".format(angle), "PSWAP({:.3g})".format(angle)],
699 )
701 def to_ir(self, target: QubitSet):
702 return ir.PSwap(targets=[target[0], target[1]], angle=self.angle)
704 def to_matrix(self) -> np.ndarray:
705 return np.array(
706 [
707 [1.0, 0.0, 0.0, 0.0],
708 [0.0, 0.0, np.exp(1j * self.angle), 0.0],
709 [0.0, np.exp(1j * self.angle), 0.0, 0.0],
710 [0.0, 0.0, 0.0, 1.0],
711 ],
712 dtype=complex,
713 )
715 @staticmethod
716 @circuit.subroutine(register=True)
717 def pswap(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
718 """Registers this function into the circuit class.
720 Args:
721 target1 (Qubit or int): Target qubit 1 index.
722 target2 (Qubit or int): Target qubit 2 index.
724 Returns:
725 Instruction: PSwap instruction.
727 Examples:
728 >>> circ = Circuit().pswap(0, 1, 0.15)
729 """
730 return Instruction(Gate.PSwap(angle), target=[target1, target2])
733Gate.register_gate(PSwap)
736class XY(AngledGate):
737 """XY gate.
739 Args:
740 angle (float): angle in radians.
741 """
743 def __init__(self, angle: float):
744 super().__init__(
745 angle=angle,
746 qubit_count=2,
747 ascii_symbols=["XY({:.3g})".format(angle), "XY({:.3g})".format(angle)],
748 )
750 def to_ir(self, target: QubitSet):
751 return ir.XY(targets=[target[0], target[1]], angle=self.angle)
753 def to_matrix(self) -> np.ndarray:
754 cos = np.cos(self.angle / 2)
755 sin = np.sin(self.angle / 2)
756 return np.array(
757 [
758 [1.0, 0.0, 0.0, 0.0],
759 [0.0, cos, 1.0j * sin, 0.0],
760 [0.0, 1.0j * sin, cos, 0.0],
761 [0.0, 0.0, 0.0, 1.0],
762 ],
763 dtype=complex,
764 )
766 @staticmethod
767 @circuit.subroutine(register=True)
768 def xy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
769 """Registers this function into the circuit class.
771 Args:
772 target1 (Qubit or int): Target qubit 1 index.
773 target2 (Qubit or int): Target qubit 2 index.
775 Returns:
776 Instruction: XY instruction.
778 Examples:
779 >>> circ = Circuit().xy(0, 1, 0.15)
780 """
781 return Instruction(Gate.XY(angle), target=[target1, target2])
784Gate.register_gate(XY)
787class CPhaseShift(AngledGate):
788 """Controlled phase shift gate.
790 Args:
791 angle (float): angle in radians.
792 """
794 def __init__(self, angle: float):
795 super().__init__(
796 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE({:.3g})".format(angle)]
797 )
799 def to_ir(self, target: QubitSet):
800 return ir.CPhaseShift(control=target[0], target=target[1], angle=self.angle)
802 def to_matrix(self) -> np.ndarray:
803 return np.diag([1.0, 1.0, 1.0, np.exp(1j * self.angle)])
805 @staticmethod
806 @circuit.subroutine(register=True)
807 def cphaseshift(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
808 """Registers this function into the circuit class.
810 Args:
811 control (Qubit or int): Control qubit index.
812 target (Qubit or int): Target qubit index.
813 angle (float): Angle in radians.
815 Returns:
816 Instruction: CPhaseShift instruction.
818 Examples:
819 >>> circ = Circuit().cphaseshift(0, 1, 0.15)
820 """
821 return Instruction(Gate.CPhaseShift(angle), target=[control, target])
824Gate.register_gate(CPhaseShift)
827class CPhaseShift00(AngledGate):
828 """Controlled phase shift gate for phasing the \\|00> state.
830 Args:
831 angle (float): angle in radians.
832 """
834 def __init__(self, angle: float):
835 super().__init__(
836 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE00({:.3g})".format(angle)]
837 )
839 def to_ir(self, target: QubitSet):
840 return ir.CPhaseShift00(control=target[0], target=target[1], angle=self.angle)
842 def to_matrix(self) -> np.ndarray:
843 return np.diag([np.exp(1j * self.angle), 1.0, 1.0, 1.0])
845 @staticmethod
846 @circuit.subroutine(register=True)
847 def cphaseshift00(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
848 """Registers this function into the circuit class.
850 Args:
851 control (Qubit or int): Control qubit index.
852 target (Qubit or int): Target qubit index.
853 angle (float): Angle in radians.
855 Returns:
856 Instruction: CPhaseShift00 instruction.
858 Examples:
859 >>> circ = Circuit().cphaseshift00(0, 1, 0.15)
860 """
861 return Instruction(Gate.CPhaseShift00(angle), target=[control, target])
864Gate.register_gate(CPhaseShift00)
867class CPhaseShift01(AngledGate):
868 """Controlled phase shift gate for phasing the \\|01> state.
870 Args:
871 angle (float): angle in radians.
872 """
874 def __init__(self, angle: float):
875 super().__init__(
876 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE01({:.3g})".format(angle)]
877 )
879 def to_ir(self, target: QubitSet):
880 return ir.CPhaseShift01(control=target[0], target=target[1], angle=self.angle)
882 def to_matrix(self) -> np.ndarray:
883 return np.diag([1.0, np.exp(1j * self.angle), 1.0, 1.0])
885 @staticmethod
886 @circuit.subroutine(register=True)
887 def cphaseshift01(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
888 """Registers this function into the circuit class.
890 Args:
891 control (Qubit or int): Control qubit index.
892 target (Qubit or int): Target qubit index.
893 angle (float): Angle in radians.
895 Returns:
896 Instruction: CPhaseShift01 instruction.
898 Examples:
899 >>> circ = Circuit().cphaseshift01(0, 1, 0.15)
900 """
901 return Instruction(Gate.CPhaseShift01(angle), target=[control, target])
904Gate.register_gate(CPhaseShift01)
907class CPhaseShift10(AngledGate):
908 """Controlled phase shift gate for phasing the \\|10> state.
910 Args:
911 angle (float): angle in radians.
912 """
914 def __init__(self, angle: float):
915 super().__init__(
916 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE10({:.3g})".format(angle)]
917 )
919 def to_ir(self, target: QubitSet):
920 return ir.CPhaseShift10(control=target[0], target=target[1], angle=self.angle)
922 def to_matrix(self) -> np.ndarray:
923 return np.diag([1.0, 1.0, np.exp(1j * self.angle), 1.0])
925 @staticmethod
926 @circuit.subroutine(register=True)
927 def cphaseshift10(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
928 """Registers this function into the circuit class.
930 Args:
931 control (Qubit or int): Control qubit index.
932 target (Qubit or int): Target qubit index.
933 angle (float): Angle in radians.
935 Returns:
936 Instruction: CPhaseShift10 instruction.
938 Examples:
939 >>> circ = Circuit().cphaseshift10(0, 1, 0.15)
940 """
941 return Instruction(Gate.CPhaseShift10(angle), target=[control, target])
944Gate.register_gate(CPhaseShift10)
947class CY(Gate):
948 """Controlled Pauli-Y gate."""
950 def __init__(self):
951 super().__init__(qubit_count=2, ascii_symbols=["C", "Y"])
953 def to_ir(self, target: QubitSet):
954 return ir.CY(control=target[0], target=target[1])
956 def to_matrix(self) -> np.ndarray:
957 return np.array(
958 [
959 [1.0, 0.0, 0.0, 0.0],
960 [0.0, 1.0, 0.0, 0.0],
961 [0.0, 0.0, 0.0, -1.0j],
962 [0.0, 0.0, +1.0j, 0.0],
963 ],
964 dtype=complex,
965 )
967 @staticmethod
968 @circuit.subroutine(register=True)
969 def cy(control: QubitInput, target: QubitInput) -> Instruction:
970 """Registers this function into the circuit class.
972 Args:
973 control (Qubit or int): Control qubit index.
974 target (Qubit or int): Target qubit index.
976 Returns:
977 Instruction: CY instruction.
979 Examples:
980 >>> circ = Circuit().cy(0, 1)
981 """
982 return Instruction(Gate.CY(), target=[control, target])
985Gate.register_gate(CY)
988class CZ(Gate):
989 """Controlled Pauli-Z gate."""
991 def __init__(self):
992 super().__init__(qubit_count=2, ascii_symbols=["C", "Z"])
994 def to_ir(self, target: QubitSet):
995 return ir.CZ(control=target[0], target=target[1])
997 def to_matrix(self) -> np.ndarray:
998 return np.diag([1.0, 1.0, 1.0, -1.0])
1000 @staticmethod
1001 @circuit.subroutine(register=True)
1002 def cz(control: QubitInput, target: QubitInput) -> Instruction:
1003 """Registers this function into the circuit class.
1005 Args:
1006 control (Qubit or int): Control qubit index.
1007 target (Qubit or int): Target qubit index.
1009 Returns:
1010 Instruction: CZ instruction.
1012 Examples:
1013 >>> circ = Circuit().cz(0, 1)
1014 """
1015 return Instruction(Gate.CZ(), target=[control, target])
1018Gate.register_gate(CZ)
1021class XX(AngledGate):
1022 """Ising XX coupling gate.
1024 Args:
1025 angle (float): angle in radians.
1026 """
1028 def __init__(self, angle: float):
1029 super().__init__(
1030 angle=angle,
1031 qubit_count=2,
1032 ascii_symbols=["XX({:.3g})".format(angle), "XX({:.3g})".format(angle)],
1033 )
1035 def to_ir(self, target: QubitSet):
1036 return ir.XX(targets=[target[0], target[1]], angle=self.angle)
1038 def to_matrix(self) -> np.ndarray:
1039 return (1 / math.sqrt(2)) * np.array(
1040 [
1041 [1.0, 0.0, 0.0, -1.0j * np.exp(1.0j * self.angle)],
1042 [0.0, 1.0, -1.0j, 0.0],
1043 [0.0, -1.0j, 1.0, 0.0],
1044 [-1.0j * np.exp(-1.0j * self.angle), 0.0, 0.0, 1.0],
1045 ],
1046 dtype=complex,
1047 )
1049 @staticmethod
1050 @circuit.subroutine(register=True)
1051 def xx(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1052 """Registers this function into the circuit class.
1054 Args:
1055 target1 (Qubit or int): Target qubit 1 index.
1056 target2 (Qubit or int): Target qubit 2 index.
1057 angle (float): Angle in radians.
1059 Returns:
1060 Instruction: XX instruction.
1062 Examples:
1063 >>> circ = Circuit().xx(0, 1, 0.15)
1064 """
1065 return Instruction(Gate.XX(angle), target=[target1, target2])
1068Gate.register_gate(XX)
1071class YY(AngledGate):
1072 """Ising YY coupling gate.
1074 Args:
1075 angle (float): angle in radians.
1076 """
1078 def __init__(self, angle: float):
1079 super().__init__(
1080 angle=angle,
1081 qubit_count=2,
1082 ascii_symbols=["YY({:.3g})".format(angle), "YY({:.3g})".format(angle)],
1083 )
1085 def to_ir(self, target: QubitSet):
1086 return ir.YY(targets=[target[0], target[1]], angle=self.angle)
1088 def to_matrix(self) -> np.ndarray:
1089 cos = np.cos(self.angle)
1090 sin = np.sin(self.angle)
1091 return np.array(
1092 [
1093 [cos, 0.0, 0.0, 1.0j * sin],
1094 [0.0, cos, -1.0j * sin, 0.0],
1095 [0.0, -1.0j * sin, cos, 0.0],
1096 [1.0j * sin, 0.0, 0.0, cos],
1097 ],
1098 dtype=complex,
1099 )
1101 @staticmethod
1102 @circuit.subroutine(register=True)
1103 def yy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1104 """Registers this function into the circuit class.
1106 Args:
1107 target1 (Qubit or int): Target qubit 1 index.
1108 target2 (Qubit or int): Target qubit 2 index.
1109 angle (float): Angle in radians.
1111 Returns:
1112 Instruction: YY instruction.
1114 Examples:
1115 >>> circ = Circuit().yy(0, 1, 0.15)
1116 """
1117 return Instruction(Gate.YY(angle), target=[target1, target2])
1120Gate.register_gate(YY)
1123class ZZ(AngledGate):
1124 """Ising ZZ coupling gate.
1126 Args:
1127 angle (float): angle in radians.
1128 """
1130 def __init__(self, angle: float):
1131 super().__init__(
1132 angle=angle,
1133 qubit_count=2,
1134 ascii_symbols=["ZZ({:.3g})".format(angle), "ZZ({:.3g})".format(angle)],
1135 )
1137 def to_ir(self, target: QubitSet):
1138 return ir.ZZ(targets=[target[0], target[1]], angle=self.angle)
1140 def to_matrix(self) -> np.ndarray:
1141 return np.array(
1142 [
1143 [np.exp(1j * (self.angle / 2)), 0.0, 0.0, 0.0],
1144 [0.0, np.exp(-1j * (self.angle / 2)), 0.0, 0.0],
1145 [0.0, 0.0, np.exp(-1j * (self.angle / 2)), 0.0],
1146 [0.0, 0.0, 0.0, np.exp(1j * (self.angle / 2))],
1147 ],
1148 dtype=complex,
1149 )
1151 @staticmethod
1152 @circuit.subroutine(register=True)
1153 def zz(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1154 """Registers this function into the circuit class.
1156 Args:
1157 target1 (Qubit or int): Target qubit 1 index.
1158 target2 (Qubit or int): Target qubit 2 index.
1159 angle (float): Angle in radians.
1161 Returns:
1162 Instruction: ZZ instruction.
1164 Examples:
1165 >>> circ = Circuit().zz(0, 1, 0.15)
1166 """
1167 return Instruction(Gate.ZZ(angle), target=[target1, target2])
1170Gate.register_gate(ZZ)
1173# Three qubit gates #
1176class CCNot(Gate):
1177 """CCNOT gate or Toffoli gate."""
1179 def __init__(self):
1180 super().__init__(qubit_count=3, ascii_symbols=["C", "C", "X"])
1182 def to_ir(self, target: QubitSet):
1183 return ir.CCNot(controls=[target[0], target[1]], target=target[2])
1185 def to_matrix(self) -> np.ndarray:
1186 return np.array(
1187 [
1188 [1, 0, 0, 0, 0, 0, 0, 0],
1189 [0, 1, 0, 0, 0, 0, 0, 0],
1190 [0, 0, 1, 0, 0, 0, 0, 0],
1191 [0, 0, 0, 1, 0, 0, 0, 0],
1192 [0, 0, 0, 0, 1, 0, 0, 0],
1193 [0, 0, 0, 0, 0, 1, 0, 0],
1194 [0, 0, 0, 0, 0, 0, 0, 1],
1195 [0, 0, 0, 0, 0, 0, 1, 0],
1196 ],
1197 dtype=complex,
1198 )
1200 @staticmethod
1201 @circuit.subroutine(register=True)
1202 def ccnot(control1: QubitInput, control2: QubitInput, target: QubitInput) -> Instruction:
1203 """Registers this function into the circuit class.
1205 Args:
1206 control1 (Qubit or int): Control qubit 1 index.
1207 control2 (Qubit or int): Control qubit 2 index.
1208 target (Qubit or int): Target qubit index.
1210 Returns:
1211 Instruction: CCNot instruction.
1213 Examples:
1214 >>> circ = Circuit().ccnot(0, 1, 2)
1215 """
1216 return Instruction(Gate.CCNot(), target=[control1, control2, target])
1219Gate.register_gate(CCNot)
1222class CSwap(Gate):
1223 """Controlled Swap gate."""
1225 def __init__(self):
1226 super().__init__(qubit_count=3, ascii_symbols=["C", "SWAP", "SWAP"])
1228 def to_ir(self, target: QubitSet):
1229 return ir.CSwap(control=target[0], targets=[target[1], target[2]])
1231 def to_matrix(self) -> np.ndarray:
1232 return np.array(
1233 [
1234 [1, 0, 0, 0, 0, 0, 0, 0],
1235 [0, 1, 0, 0, 0, 0, 0, 0],
1236 [0, 0, 1, 0, 0, 0, 0, 0],
1237 [0, 0, 0, 1, 0, 0, 0, 0],
1238 [0, 0, 0, 0, 1, 0, 0, 0],
1239 [0, 0, 0, 0, 0, 0, 1, 0],
1240 [0, 0, 0, 0, 0, 1, 0, 0],
1241 [0, 0, 0, 0, 0, 0, 0, 1],
1242 ],
1243 dtype=complex,
1244 )
1246 @staticmethod
1247 @circuit.subroutine(register=True)
1248 def cswap(control: QubitInput, target1: QubitInput, target2: QubitInput) -> Instruction:
1249 """Registers this function into the circuit class.
1251 Args:
1252 control (Qubit or int): Control qubit index
1253 target1 (Qubit or int): Target qubit 1 index.
1254 target2 (Qubit or int): Target qubit 2 index.
1256 Returns:
1257 Instruction: CSwap instruction.
1259 Examples:
1260 >>> circ = Circuit().cswap(0, 1, 2)
1261 """
1262 return Instruction(Gate.CSwap(), target=[control, target1, target2])
1265Gate.register_gate(CSwap)
1268class Unitary(Gate):
1269 """Arbitrary unitary gate
1271 Args:
1272 matrix (numpy.ndarray): Unitary matrix which defines the gate.
1273 display_name (str): Name to be used for an instance of this unitary gate
1274 for circuit diagrams. Defaults to `U`.
1276 Raises:
1277 ValueError: If `matrix` is not a two-dimensional square matrix,
1278 or has a dimension length which is not a positive exponent of 2,
1279 or is non-unitary.
1280 """
1282 def __init__(self, matrix: np.ndarray, display_name: str = "U"):
1283 if len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]:
1284 raise ValueError(f"{matrix} is not a two-dimensional square matrix")
1286 self._matrix = np.array(matrix, dtype=complex)
1287 qubit_count = int(np.log2(self._matrix.shape[0]))
1288 if 2 ** qubit_count != self._matrix.shape[0] or qubit_count < 1:
1289 raise ValueError(
1290 f"`matrix` dimension {self._matrix.shape[0]} is not a positive exponent of 2"
1291 )
1293 if not Unitary._is_unitary(self._matrix):
1294 raise ValueError(f"{self._matrix} is not unitary")
1296 super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count)
1298 def to_matrix(self):
1299 return np.array(self._matrix)
1301 def to_ir(self, target: QubitSet):
1302 return ir.Unitary(
1303 targets=[qubit for qubit in target],
1304 matrix=Unitary._transform_matrix_to_ir(self._matrix),
1305 )
1307 @staticmethod
1308 def _is_unitary(matrix: np.ndarray):
1309 return np.allclose(np.eye(len(matrix)), matrix.dot(matrix.T.conj()))
1311 @staticmethod
1312 def _transform_matrix_to_ir(matrix: np.ndarray):
1313 return [[[element.real, element.imag] for element in row] for row in matrix.tolist()]
1315 @staticmethod
1316 @circuit.subroutine(register=True)
1317 def unitary(targets: QubitSet, matrix: np.ndarray, display_name: str = "U") -> Instruction:
1318 """Registers this function into the circuit class.
1320 Args:
1321 targets (QubitSet): Target qubits.
1322 matrix (numpy.ndarray): Unitary matrix which defines the gate. Matrix should be
1323 compatible with the supplied targets, with 2 ** len(targets) == matrix.shape[0].
1324 display_name (str): Name to be used for an instance of this unitary gate
1325 for circuit diagrams. Defaults to `U`.
1327 Returns:
1328 Instruction: Unitary instruction.
1330 Raises:
1331 ValueError: If `matrix` is not a two-dimensional square matrix,
1332 or has a dimension length which is not compatible with the `targets`,
1333 or is non-unitary,
1335 Examples:
1336 >>> circ = Circuit().unitary(matrix=np.array([[0, 1],[1, 0]]), targets=[0])
1337 """
1338 if 2 ** len(targets) != matrix.shape[0]: 1338 ↛ 1339line 1338 didn't jump to line 1339, because the condition on line 1338 was never true
1339 raise ValueError("Dimensions of the supplied unitary are incompatible with the targets")
1341 return Instruction(Gate.Unitary(matrix, display_name), target=targets)
1344Gate.register_gate(Unitary)