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.quantum_operator_helpers import (
24 is_unitary,
25 verify_quantum_operator_matrix_dimensions,
26)
27from braket.circuits.qubit import QubitInput
28from braket.circuits.qubit_set import QubitSet, QubitSetInput
30"""
31To add a new gate:
32 1. Implement the class and extend `Gate`
33 2. Add a method with the `@circuit.subroutine(register=True)` decorator. Method name
34 will be added into the `Circuit` class. This method is the default way
35 clients add this gate to a circuit.
36 3. Register the class with the `Gate` class via `Gate.register_gate()`.
37"""
39# Single qubit gates #
42class H(Gate):
43 """Hadamard gate."""
45 def __init__(self):
46 super().__init__(qubit_count=1, ascii_symbols=["H"])
48 def to_ir(self, target: QubitSet):
49 return ir.H.construct(target=target[0])
51 def to_matrix(self) -> np.ndarray:
52 return 1.0 / np.sqrt(2.0) * np.array([[1.0, 1.0], [1.0, -1.0]], dtype=complex)
54 @staticmethod
55 @circuit.subroutine(register=True)
56 def h(target: QubitSetInput) -> Iterable[Instruction]:
57 """Registers this function into the circuit class.
59 Args:
60 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
62 Returns:
63 Iterable[Instruction]: `Iterable` of H instructions.
65 Examples:
66 >>> circ = Circuit().h(0)
67 >>> circ = Circuit().h([0, 1, 2])
68 """
69 return [Instruction(Gate.H(), target=qubit) for qubit in QubitSet(target)]
72Gate.register_gate(H)
75class I(Gate): # noqa: E742, E261
76 """Identity gate."""
78 def __init__(self):
79 super().__init__(qubit_count=1, ascii_symbols=["I"])
81 def to_ir(self, target: QubitSet):
82 return ir.I.construct(target=target[0])
84 def to_matrix(self) -> np.ndarray:
85 return np.array([[1.0, 0.0], [0.0, 1.0]], dtype=complex)
87 @staticmethod
88 @circuit.subroutine(register=True)
89 def i(target: QubitSetInput) -> Iterable[Instruction]:
90 """Registers this function into the circuit class.
92 Args:
93 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
95 Returns:
96 Iterable[Instruction]: `Iterable` of I instructions.
98 Examples:
99 >>> circ = Circuit().i(0)
100 >>> circ = Circuit().i([0, 1, 2])
101 """
102 return [Instruction(Gate.I(), target=qubit) for qubit in QubitSet(target)]
105Gate.register_gate(I)
108class X(Gate):
109 """Pauli-X gate."""
111 def __init__(self):
112 super().__init__(qubit_count=1, ascii_symbols=["X"])
114 def to_ir(self, target: QubitSet):
115 return ir.X.construct(target=target[0])
117 def to_matrix(self) -> np.ndarray:
118 return np.array([[0.0, 1.0], [1.0, 0.0]], dtype=complex)
120 @staticmethod
121 @circuit.subroutine(register=True)
122 def x(target: QubitSetInput) -> Iterable[Instruction]:
123 """Registers this function into the circuit class.
125 Args:
126 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
128 Returns:
129 Iterable[Instruction]: `Iterable` of X instructions.
131 Examples:
132 >>> circ = Circuit().x(0)
133 >>> circ = Circuit().x([0, 1, 2])
134 """
135 return [Instruction(Gate.X(), target=qubit) for qubit in QubitSet(target)]
138Gate.register_gate(X)
141class Y(Gate):
142 """Pauli-Y gate."""
144 def __init__(self):
145 super().__init__(qubit_count=1, ascii_symbols=["Y"])
147 def to_ir(self, target: QubitSet):
148 return ir.Y.construct(target=target[0])
150 def to_matrix(self) -> np.ndarray:
151 return np.array([[0.0, -1.0j], [1.0j, 0.0]], dtype=complex)
153 @staticmethod
154 @circuit.subroutine(register=True)
155 def y(target: QubitSetInput) -> Iterable[Instruction]:
156 """Registers this function into the circuit class.
158 Args:
159 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
161 Returns:
162 Iterable[Instruction]: `Iterable` of Y instructions.
164 Examples:
165 >>> circ = Circuit().y(0)
166 >>> circ = Circuit().y([0, 1, 2])
167 """
168 return [Instruction(Gate.Y(), target=qubit) for qubit in QubitSet(target)]
171Gate.register_gate(Y)
174class Z(Gate):
175 """Pauli-Z gate."""
177 def __init__(self):
178 super().__init__(qubit_count=1, ascii_symbols=["Z"])
180 def to_ir(self, target: QubitSet):
181 return ir.Z.construct(target=target[0])
183 def to_matrix(self) -> np.ndarray:
184 return np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex)
186 @staticmethod
187 @circuit.subroutine(register=True)
188 def z(target: QubitSetInput) -> Iterable[Instruction]:
189 """Registers this function into the circuit class.
191 Args:
192 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
194 Returns:
195 Iterable[Instruction]: `Iterable` of Z instructions.
197 Examples:
198 >>> circ = Circuit().z(0)
199 >>> circ = Circuit().z([0, 1, 2])
200 """
201 return [Instruction(Gate.Z(), target=qubit) for qubit in QubitSet(target)]
204Gate.register_gate(Z)
207class S(Gate):
208 """S gate."""
210 def __init__(self):
211 super().__init__(qubit_count=1, ascii_symbols=["S"])
213 def to_ir(self, target: QubitSet):
214 return ir.S.construct(target=target[0])
216 def to_matrix(self) -> np.ndarray:
218 return np.array([[1.0, 0.0], [0.0, 1.0j]], dtype=complex)
220 @staticmethod
221 @circuit.subroutine(register=True)
222 def s(target: QubitSetInput) -> Iterable[Instruction]:
223 """Registers this function into the circuit class.
225 Args:
226 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
228 Returns:
229 Iterable[Instruction]: `Iterable` of S instructions.
231 Examples:
232 >>> circ = Circuit().s(0)
233 >>> circ = Circuit().s([0, 1, 2])
234 """
235 return [Instruction(Gate.S(), target=qubit) for qubit in QubitSet(target)]
238Gate.register_gate(S)
241class Si(Gate):
242 """Conjugate transpose of S gate."""
244 def __init__(self):
245 super().__init__(qubit_count=1, ascii_symbols=["Si"])
247 def to_ir(self, target: QubitSet):
248 return ir.Si.construct(target=target[0])
250 def to_matrix(self) -> np.ndarray:
251 return np.array([[1, 0], [0, -1j]], dtype=complex)
253 @staticmethod
254 @circuit.subroutine(register=True)
255 def si(target: QubitSetInput) -> Iterable[Instruction]:
256 """Registers this function into the circuit class.
258 Args:
259 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
261 Returns:
262 Iterable[Instruction]: Iterable of Si instructions.
264 Examples:
265 >>> circ = Circuit().si(0)
266 >>> circ = Circuit().si([0, 1, 2])
267 """
268 return [Instruction(Gate.Si(), target=qubit) for qubit in QubitSet(target)]
271Gate.register_gate(Si)
274class T(Gate):
275 """T gate."""
277 def __init__(self):
278 super().__init__(qubit_count=1, ascii_symbols=["T"])
280 def to_ir(self, target: QubitSet):
281 return ir.T.construct(target=target[0])
283 def to_matrix(self) -> np.ndarray:
284 return np.array([[1.0, 0.0], [0.0, np.exp(1j * np.pi / 4)]], dtype=complex)
286 @staticmethod
287 @circuit.subroutine(register=True)
288 def t(target: QubitSetInput) -> Iterable[Instruction]:
289 """Registers this function into the circuit class.
291 Args:
292 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
294 Returns:
295 Iterable[Instruction]: `Iterable` of T instructions.
297 Examples:
298 >>> circ = Circuit().t(0)
299 >>> circ = Circuit().t([0, 1, 2])
300 """
301 return [Instruction(Gate.T(), target=qubit) for qubit in QubitSet(target)]
304Gate.register_gate(T)
307class Ti(Gate):
308 """Conjugate transpose of T gate."""
310 def __init__(self):
311 super().__init__(qubit_count=1, ascii_symbols=["Ti"])
313 def to_ir(self, target: QubitSet):
314 return ir.Ti.construct(target=target[0])
316 def to_matrix(self) -> np.ndarray:
317 return np.array([[1.0, 0.0], [0.0, np.exp(-1j * np.pi / 4)]], dtype=complex)
319 @staticmethod
320 @circuit.subroutine(register=True)
321 def ti(target: QubitSetInput) -> Iterable[Instruction]:
322 """Registers this function into the circuit class.
324 Args:
325 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
327 Returns:
328 Iterable[Instruction]: `Iterable` of Ti instructions.
330 Examples:
331 >>> circ = Circuit().ti(0)
332 >>> circ = Circuit().ti([0, 1, 2])
333 """
334 return [Instruction(Gate.Ti(), target=qubit) for qubit in QubitSet(target)]
337Gate.register_gate(Ti)
340class V(Gate):
341 """Square root of not gate."""
343 def __init__(self):
344 super().__init__(qubit_count=1, ascii_symbols=["V"])
346 def to_ir(self, target: QubitSet):
347 return ir.V.construct(target=target[0])
349 def to_matrix(self) -> np.ndarray:
350 return np.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=complex)
352 @staticmethod
353 @circuit.subroutine(register=True)
354 def v(target: QubitSetInput) -> Iterable[Instruction]:
355 """Registers this function into the circuit class.
357 Args:
358 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
360 Returns:
361 Iterable[Instruction]: `Iterable` of V instructions.
363 Examples:
364 >>> circ = Circuit().v(0)
365 >>> circ = Circuit().v([0, 1, 2])
366 """
367 return [Instruction(Gate.V(), target=qubit) for qubit in QubitSet(target)]
370Gate.register_gate(V)
373class Vi(Gate):
374 """Conjugate transpose of square root of not gate."""
376 def __init__(self):
377 super().__init__(qubit_count=1, ascii_symbols=["Vi"])
379 def to_ir(self, target: QubitSet):
380 return ir.Vi.construct(target=target[0])
382 def to_matrix(self) -> np.ndarray:
383 return np.array(([[0.5 - 0.5j, 0.5 + 0.5j], [0.5 + 0.5j, 0.5 - 0.5j]]), dtype=complex)
385 @staticmethod
386 @circuit.subroutine(register=True)
387 def vi(target: QubitSetInput) -> Iterable[Instruction]:
388 """Registers this function into the circuit class.
390 Args:
391 target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
393 Returns:
394 Iterable[Instruction]: `Iterable` of Vi instructions.
396 Examples:
397 >>> circ = Circuit().vi(0)
398 >>> circ = Circuit().vi([0, 1, 2])
399 """
400 return [Instruction(Gate.Vi(), target=qubit) for qubit in QubitSet(target)]
403Gate.register_gate(Vi)
406# Single qubit gates with rotation #
409class Rx(AngledGate):
410 """X-axis rotation gate.
412 Args:
413 angle (float): angle in radians.
414 """
416 def __init__(self, angle: float):
417 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rx({:.3g})".format(angle)])
419 def to_ir(self, target: QubitSet):
420 return ir.Rx.construct(target=target[0], angle=self.angle)
422 def to_matrix(self) -> np.ndarray:
423 cos = np.cos(self.angle / 2)
424 sin = np.sin(self.angle / 2)
425 return np.array([[cos, -1j * sin], [-1j * sin, cos]], dtype=complex)
427 @staticmethod
428 @circuit.subroutine(register=True)
429 def rx(target: QubitInput, angle: float) -> Instruction:
430 """Registers this function into the circuit class.
432 Args:
433 target (Qubit or int): Target qubit index.
434 angle (float): Angle in radians.
436 Returns:
437 Instruction: Rx instruction.
439 Examples:
440 >>> circ = Circuit().rx(0, 0.15)
441 """
442 return [Instruction(Gate.Rx(angle), target=qubit) for qubit in QubitSet(target)]
445Gate.register_gate(Rx)
448class Ry(AngledGate):
449 """Y-axis rotation gate.
451 Args:
452 angle (float): angle in radians.
453 """
455 def __init__(self, angle: float):
456 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Ry({:.3g})".format(angle)])
458 def to_ir(self, target: QubitSet):
459 return ir.Ry.construct(target=target[0], angle=self.angle)
461 def to_matrix(self) -> np.ndarray:
462 cos = np.cos(self.angle / 2)
463 sin = np.sin(self.angle / 2)
464 return np.array([[cos, -sin], [+sin, cos]], dtype=complex)
466 @staticmethod
467 @circuit.subroutine(register=True)
468 def ry(target: QubitInput, angle: float) -> Instruction:
469 """Registers this function into the circuit class.
471 Args:
472 target (Qubit or int): Target qubit index.
473 angle (float): Angle in radians.
475 Returns:
476 Instruction: Ry instruction.
478 Examples:
479 >>> circ = Circuit().ry(0, 0.15)
480 """
481 return [Instruction(Gate.Ry(angle), target=qubit) for qubit in QubitSet(target)]
484Gate.register_gate(Ry)
487class Rz(AngledGate):
488 """Z-axis rotation gate.
490 Args:
491 angle (float): angle in radians.
492 """
494 def __init__(self, angle: float):
495 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rz({:.3g})".format(angle)])
497 def to_ir(self, target: QubitSet):
498 return ir.Rz.construct(target=target[0], angle=self.angle)
500 def to_matrix(self) -> np.ndarray:
501 return np.array(
502 [[np.exp(-1j * self.angle / 2), 0], [0, np.exp(1j * self.angle / 2)]], dtype=complex
503 )
505 @staticmethod
506 @circuit.subroutine(register=True)
507 def rz(target: QubitInput, angle: float) -> Instruction:
508 """Registers this function into the circuit class.
510 Args:
511 target (Qubit or int): Target qubit index.
512 angle (float): Angle in radians.
514 Returns:
515 Instruction: Rz instruction.
517 Examples:
518 >>> circ = Circuit().rz(0, 0.15)
519 """
520 return [Instruction(Gate.Rz(angle), target=qubit) for qubit in QubitSet(target)]
523Gate.register_gate(Rz)
526class PhaseShift(AngledGate):
527 """Phase shift gate.
529 Args:
530 angle (float): angle in radians.
531 """
533 def __init__(self, angle: float):
534 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["PHASE({:.3g})".format(angle)])
536 def to_ir(self, target: QubitSet):
537 return ir.PhaseShift.construct(target=target[0], angle=self.angle)
539 def to_matrix(self) -> np.ndarray:
540 return np.array([[1.0, 0.0], [0.0, np.exp(1j * self.angle)]], dtype=complex)
542 @staticmethod
543 @circuit.subroutine(register=True)
544 def phaseshift(target: QubitInput, angle: float) -> Instruction:
545 """Registers this function into the circuit class.
547 Args:
548 target (Qubit or int): Target qubit index.
549 angle (float): Angle in radians.
551 Returns:
552 Instruction: PhaseShift instruction.
554 Examples:
555 >>> circ = Circuit().phaseshift(0, 0.15)
556 """
557 return [Instruction(Gate.PhaseShift(angle), target=qubit) for qubit in QubitSet(target)]
560Gate.register_gate(PhaseShift)
563# Two qubit gates #
566class CNot(Gate):
567 """Controlled NOT gate."""
569 def __init__(self):
570 super().__init__(qubit_count=2, ascii_symbols=["C", "X"])
572 def to_ir(self, target: QubitSet):
573 return ir.CNot.construct(control=target[0], target=target[1])
575 def to_matrix(self) -> np.ndarray:
576 return np.array(
577 [
578 [1.0, 0.0, 0.0, 0.0],
579 [0.0, 1.0, 0.0, 0.0],
580 [0.0, 0.0, 0.0, 1.0],
581 [0.0, 0.0, 1.0, 0.0],
582 ],
583 dtype=complex,
584 )
586 @staticmethod
587 @circuit.subroutine(register=True)
588 def cnot(control: QubitInput, target: QubitInput) -> Instruction:
589 """Registers this function into the circuit class.
591 Args:
592 control (Qubit or int): Control qubit index.
593 target (Qubit or int): Target qubit index.
595 Returns:
596 Instruction: CNot instruction.
598 Examples:
599 >>> circ = Circuit().cnot(0, 1)
600 """
601 return Instruction(Gate.CNot(), target=[control, target])
604Gate.register_gate(CNot)
607class Swap(Gate):
608 """Swap gate."""
610 def __init__(self):
611 super().__init__(qubit_count=2, ascii_symbols=["SWAP", "SWAP"])
613 def to_ir(self, target: QubitSet):
614 return ir.Swap.construct(targets=[target[0], target[1]])
616 def to_matrix(self) -> np.ndarray:
617 return np.array(
618 [
619 [1.0, 0.0, 0.0, 0.0],
620 [0.0, 0.0, 1.0, 0.0],
621 [0.0, 1.0, 0.0, 0.0],
622 [0.0, 0.0, 0.0, 1.0],
623 ],
624 dtype=complex,
625 )
627 @staticmethod
628 @circuit.subroutine(register=True)
629 def swap(target1: QubitInput, target2: QubitInput) -> Instruction:
630 """Registers this function into the circuit class.
632 Args:
633 target1 (Qubit or int): Target qubit 1 index.
634 target2 (Qubit or int): Target qubit 2 index.
636 Returns:
637 Instruction: Swap instruction.
639 Examples:
640 >>> circ = Circuit().swap(0, 1)
641 """
642 return Instruction(Gate.Swap(), target=[target1, target2])
645Gate.register_gate(Swap)
648class ISwap(Gate):
649 """ISwap gate."""
651 def __init__(self):
652 super().__init__(qubit_count=2, ascii_symbols=["ISWAP", "ISWAP"])
654 def to_ir(self, target: QubitSet):
655 return ir.ISwap.construct(targets=[target[0], target[1]])
657 def to_matrix(self) -> np.ndarray:
658 return np.array(
659 [
660 [1.0, 0.0, 0.0, 0.0],
661 [0.0, 0.0, 1.0j, 0.0],
662 [0.0, 1.0j, 0.0, 0.0],
663 [0.0, 0.0, 0.0, 1.0],
664 ],
665 dtype=complex,
666 )
668 @staticmethod
669 @circuit.subroutine(register=True)
670 def iswap(target1: QubitInput, target2: QubitInput) -> Instruction:
671 """Registers this function into the circuit class.
673 Args:
674 target1 (Qubit or int): Target qubit 1 index.
675 target2 (Qubit or int): Target qubit 2 index.
677 Returns:
678 Instruction: ISwap instruction.
680 Examples:
681 >>> circ = Circuit().iswap(0, 1)
682 """
683 return Instruction(Gate.ISwap(), target=[target1, target2])
686Gate.register_gate(ISwap)
689class PSwap(AngledGate):
690 """PSwap gate.
692 Args:
693 angle (float): angle in radians.
694 """
696 def __init__(self, angle: float):
697 super().__init__(
698 angle=angle,
699 qubit_count=2,
700 ascii_symbols=["PSWAP({:.3g})".format(angle), "PSWAP({:.3g})".format(angle)],
701 )
703 def to_ir(self, target: QubitSet):
704 return ir.PSwap.construct(targets=[target[0], target[1]], angle=self.angle)
706 def to_matrix(self) -> np.ndarray:
707 return np.array(
708 [
709 [1.0, 0.0, 0.0, 0.0],
710 [0.0, 0.0, np.exp(1j * self.angle), 0.0],
711 [0.0, np.exp(1j * self.angle), 0.0, 0.0],
712 [0.0, 0.0, 0.0, 1.0],
713 ],
714 dtype=complex,
715 )
717 @staticmethod
718 @circuit.subroutine(register=True)
719 def pswap(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
720 """Registers this function into the circuit class.
722 Args:
723 target1 (Qubit or int): Target qubit 1 index.
724 target2 (Qubit or int): Target qubit 2 index.
726 Returns:
727 Instruction: PSwap instruction.
729 Examples:
730 >>> circ = Circuit().pswap(0, 1, 0.15)
731 """
732 return Instruction(Gate.PSwap(angle), target=[target1, target2])
735Gate.register_gate(PSwap)
738class XY(AngledGate):
739 """XY gate.
741 Args:
742 angle (float): angle in radians.
743 """
745 def __init__(self, angle: float):
746 super().__init__(
747 angle=angle,
748 qubit_count=2,
749 ascii_symbols=["XY({:.3g})".format(angle), "XY({:.3g})".format(angle)],
750 )
752 def to_ir(self, target: QubitSet):
753 return ir.XY.construct(targets=[target[0], target[1]], angle=self.angle)
755 def to_matrix(self) -> np.ndarray:
756 cos = np.cos(self.angle / 2)
757 sin = np.sin(self.angle / 2)
758 return np.array(
759 [
760 [1.0, 0.0, 0.0, 0.0],
761 [0.0, cos, 1.0j * sin, 0.0],
762 [0.0, 1.0j * sin, cos, 0.0],
763 [0.0, 0.0, 0.0, 1.0],
764 ],
765 dtype=complex,
766 )
768 @staticmethod
769 @circuit.subroutine(register=True)
770 def xy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
771 """Registers this function into the circuit class.
773 Args:
774 target1 (Qubit or int): Target qubit 1 index.
775 target2 (Qubit or int): Target qubit 2 index.
777 Returns:
778 Instruction: XY instruction.
780 Examples:
781 >>> circ = Circuit().xy(0, 1, 0.15)
782 """
783 return Instruction(Gate.XY(angle), target=[target1, target2])
786Gate.register_gate(XY)
789class CPhaseShift(AngledGate):
790 """Controlled phase shift gate.
792 Args:
793 angle (float): angle in radians.
794 """
796 def __init__(self, angle: float):
797 super().__init__(
798 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE({:.3g})".format(angle)]
799 )
801 def to_ir(self, target: QubitSet):
802 return ir.CPhaseShift.construct(control=target[0], target=target[1], angle=self.angle)
804 def to_matrix(self) -> np.ndarray:
805 return np.diag([1.0, 1.0, 1.0, np.exp(1j * self.angle)])
807 @staticmethod
808 @circuit.subroutine(register=True)
809 def cphaseshift(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
810 """Registers this function into the circuit class.
812 Args:
813 control (Qubit or int): Control qubit index.
814 target (Qubit or int): Target qubit index.
815 angle (float): Angle in radians.
817 Returns:
818 Instruction: CPhaseShift instruction.
820 Examples:
821 >>> circ = Circuit().cphaseshift(0, 1, 0.15)
822 """
823 return Instruction(Gate.CPhaseShift(angle), target=[control, target])
826Gate.register_gate(CPhaseShift)
829class CPhaseShift00(AngledGate):
830 """Controlled phase shift gate for phasing the \\|00> state.
832 Args:
833 angle (float): angle in radians.
834 """
836 def __init__(self, angle: float):
837 super().__init__(
838 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE00({:.3g})".format(angle)]
839 )
841 def to_ir(self, target: QubitSet):
842 return ir.CPhaseShift00.construct(control=target[0], target=target[1], angle=self.angle)
844 def to_matrix(self) -> np.ndarray:
845 return np.diag([np.exp(1j * self.angle), 1.0, 1.0, 1.0])
847 @staticmethod
848 @circuit.subroutine(register=True)
849 def cphaseshift00(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
850 """Registers this function into the circuit class.
852 Args:
853 control (Qubit or int): Control qubit index.
854 target (Qubit or int): Target qubit index.
855 angle (float): Angle in radians.
857 Returns:
858 Instruction: CPhaseShift00 instruction.
860 Examples:
861 >>> circ = Circuit().cphaseshift00(0, 1, 0.15)
862 """
863 return Instruction(Gate.CPhaseShift00(angle), target=[control, target])
866Gate.register_gate(CPhaseShift00)
869class CPhaseShift01(AngledGate):
870 """Controlled phase shift gate for phasing the \\|01> state.
872 Args:
873 angle (float): angle in radians.
874 """
876 def __init__(self, angle: float):
877 super().__init__(
878 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE01({:.3g})".format(angle)]
879 )
881 def to_ir(self, target: QubitSet):
882 return ir.CPhaseShift01.construct(control=target[0], target=target[1], angle=self.angle)
884 def to_matrix(self) -> np.ndarray:
885 return np.diag([1.0, np.exp(1j * self.angle), 1.0, 1.0])
887 @staticmethod
888 @circuit.subroutine(register=True)
889 def cphaseshift01(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
890 """Registers this function into the circuit class.
892 Args:
893 control (Qubit or int): Control qubit index.
894 target (Qubit or int): Target qubit index.
895 angle (float): Angle in radians.
897 Returns:
898 Instruction: CPhaseShift01 instruction.
900 Examples:
901 >>> circ = Circuit().cphaseshift01(0, 1, 0.15)
902 """
903 return Instruction(Gate.CPhaseShift01(angle), target=[control, target])
906Gate.register_gate(CPhaseShift01)
909class CPhaseShift10(AngledGate):
910 """Controlled phase shift gate for phasing the \\|10> state.
912 Args:
913 angle (float): angle in radians.
914 """
916 def __init__(self, angle: float):
917 super().__init__(
918 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE10({:.3g})".format(angle)]
919 )
921 def to_ir(self, target: QubitSet):
922 return ir.CPhaseShift10.construct(control=target[0], target=target[1], angle=self.angle)
924 def to_matrix(self) -> np.ndarray:
925 return np.diag([1.0, 1.0, np.exp(1j * self.angle), 1.0])
927 @staticmethod
928 @circuit.subroutine(register=True)
929 def cphaseshift10(control: QubitInput, target: QubitInput, angle: float) -> Instruction:
930 """Registers this function into the circuit class.
932 Args:
933 control (Qubit or int): Control qubit index.
934 target (Qubit or int): Target qubit index.
935 angle (float): Angle in radians.
937 Returns:
938 Instruction: CPhaseShift10 instruction.
940 Examples:
941 >>> circ = Circuit().cphaseshift10(0, 1, 0.15)
942 """
943 return Instruction(Gate.CPhaseShift10(angle), target=[control, target])
946Gate.register_gate(CPhaseShift10)
949class CY(Gate):
950 """Controlled Pauli-Y gate."""
952 def __init__(self):
953 super().__init__(qubit_count=2, ascii_symbols=["C", "Y"])
955 def to_ir(self, target: QubitSet):
956 return ir.CY.construct(control=target[0], target=target[1])
958 def to_matrix(self) -> np.ndarray:
959 return np.array(
960 [
961 [1.0, 0.0, 0.0, 0.0],
962 [0.0, 1.0, 0.0, 0.0],
963 [0.0, 0.0, 0.0, -1.0j],
964 [0.0, 0.0, +1.0j, 0.0],
965 ],
966 dtype=complex,
967 )
969 @staticmethod
970 @circuit.subroutine(register=True)
971 def cy(control: QubitInput, target: QubitInput) -> Instruction:
972 """Registers this function into the circuit class.
974 Args:
975 control (Qubit or int): Control qubit index.
976 target (Qubit or int): Target qubit index.
978 Returns:
979 Instruction: CY instruction.
981 Examples:
982 >>> circ = Circuit().cy(0, 1)
983 """
984 return Instruction(Gate.CY(), target=[control, target])
987Gate.register_gate(CY)
990class CZ(Gate):
991 """Controlled Pauli-Z gate."""
993 def __init__(self):
994 super().__init__(qubit_count=2, ascii_symbols=["C", "Z"])
996 def to_ir(self, target: QubitSet):
997 return ir.CZ.construct(control=target[0], target=target[1])
999 def to_matrix(self) -> np.ndarray:
1000 return np.diag([1.0, 1.0, 1.0, -1.0])
1002 @staticmethod
1003 @circuit.subroutine(register=True)
1004 def cz(control: QubitInput, target: QubitInput) -> Instruction:
1005 """Registers this function into the circuit class.
1007 Args:
1008 control (Qubit or int): Control qubit index.
1009 target (Qubit or int): Target qubit index.
1011 Returns:
1012 Instruction: CZ instruction.
1014 Examples:
1015 >>> circ = Circuit().cz(0, 1)
1016 """
1017 return Instruction(Gate.CZ(), target=[control, target])
1020Gate.register_gate(CZ)
1023class XX(AngledGate):
1024 """Ising XX coupling gate.
1026 Args:
1027 angle (float): angle in radians.
1028 """
1030 def __init__(self, angle: float):
1031 super().__init__(
1032 angle=angle,
1033 qubit_count=2,
1034 ascii_symbols=["XX({:.3g})".format(angle), "XX({:.3g})".format(angle)],
1035 )
1037 def to_ir(self, target: QubitSet):
1038 return ir.XX.construct(targets=[target[0], target[1]], angle=self.angle)
1040 def to_matrix(self) -> np.ndarray:
1041 return (1 / math.sqrt(2)) * np.array(
1042 [
1043 [1.0, 0.0, 0.0, -1.0j * np.exp(1.0j * self.angle)],
1044 [0.0, 1.0, -1.0j, 0.0],
1045 [0.0, -1.0j, 1.0, 0.0],
1046 [-1.0j * np.exp(-1.0j * self.angle), 0.0, 0.0, 1.0],
1047 ],
1048 dtype=complex,
1049 )
1051 @staticmethod
1052 @circuit.subroutine(register=True)
1053 def xx(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1054 """Registers this function into the circuit class.
1056 Args:
1057 target1 (Qubit or int): Target qubit 1 index.
1058 target2 (Qubit or int): Target qubit 2 index.
1059 angle (float): Angle in radians.
1061 Returns:
1062 Instruction: XX instruction.
1064 Examples:
1065 >>> circ = Circuit().xx(0, 1, 0.15)
1066 """
1067 return Instruction(Gate.XX(angle), target=[target1, target2])
1070Gate.register_gate(XX)
1073class YY(AngledGate):
1074 """Ising YY coupling gate.
1076 Args:
1077 angle (float): angle in radians.
1078 """
1080 def __init__(self, angle: float):
1081 super().__init__(
1082 angle=angle,
1083 qubit_count=2,
1084 ascii_symbols=["YY({:.3g})".format(angle), "YY({:.3g})".format(angle)],
1085 )
1087 def to_ir(self, target: QubitSet):
1088 return ir.YY.construct(targets=[target[0], target[1]], angle=self.angle)
1090 def to_matrix(self) -> np.ndarray:
1091 cos = np.cos(self.angle)
1092 sin = np.sin(self.angle)
1093 return np.array(
1094 [
1095 [cos, 0.0, 0.0, 1.0j * sin],
1096 [0.0, cos, -1.0j * sin, 0.0],
1097 [0.0, -1.0j * sin, cos, 0.0],
1098 [1.0j * sin, 0.0, 0.0, cos],
1099 ],
1100 dtype=complex,
1101 )
1103 @staticmethod
1104 @circuit.subroutine(register=True)
1105 def yy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1106 """Registers this function into the circuit class.
1108 Args:
1109 target1 (Qubit or int): Target qubit 1 index.
1110 target2 (Qubit or int): Target qubit 2 index.
1111 angle (float): Angle in radians.
1113 Returns:
1114 Instruction: YY instruction.
1116 Examples:
1117 >>> circ = Circuit().yy(0, 1, 0.15)
1118 """
1119 return Instruction(Gate.YY(angle), target=[target1, target2])
1122Gate.register_gate(YY)
1125class ZZ(AngledGate):
1126 """Ising ZZ coupling gate.
1128 Args:
1129 angle (float): angle in radians.
1130 """
1132 def __init__(self, angle: float):
1133 super().__init__(
1134 angle=angle,
1135 qubit_count=2,
1136 ascii_symbols=["ZZ({:.3g})".format(angle), "ZZ({:.3g})".format(angle)],
1137 )
1139 def to_ir(self, target: QubitSet):
1140 return ir.ZZ.construct(targets=[target[0], target[1]], angle=self.angle)
1142 def to_matrix(self) -> np.ndarray:
1143 return np.array(
1144 [
1145 [np.exp(1j * (self.angle / 2)), 0.0, 0.0, 0.0],
1146 [0.0, np.exp(-1j * (self.angle / 2)), 0.0, 0.0],
1147 [0.0, 0.0, np.exp(-1j * (self.angle / 2)), 0.0],
1148 [0.0, 0.0, 0.0, np.exp(1j * (self.angle / 2))],
1149 ],
1150 dtype=complex,
1151 )
1153 @staticmethod
1154 @circuit.subroutine(register=True)
1155 def zz(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction:
1156 """Registers this function into the circuit class.
1158 Args:
1159 target1 (Qubit or int): Target qubit 1 index.
1160 target2 (Qubit or int): Target qubit 2 index.
1161 angle (float): Angle in radians.
1163 Returns:
1164 Instruction: ZZ instruction.
1166 Examples:
1167 >>> circ = Circuit().zz(0, 1, 0.15)
1168 """
1169 return Instruction(Gate.ZZ(angle), target=[target1, target2])
1172Gate.register_gate(ZZ)
1175# Three qubit gates #
1178class CCNot(Gate):
1179 """CCNOT gate or Toffoli gate."""
1181 def __init__(self):
1182 super().__init__(qubit_count=3, ascii_symbols=["C", "C", "X"])
1184 def to_ir(self, target: QubitSet):
1185 return ir.CCNot.construct(controls=[target[0], target[1]], target=target[2])
1187 def to_matrix(self) -> np.ndarray:
1188 return np.array(
1189 [
1190 [1, 0, 0, 0, 0, 0, 0, 0],
1191 [0, 1, 0, 0, 0, 0, 0, 0],
1192 [0, 0, 1, 0, 0, 0, 0, 0],
1193 [0, 0, 0, 1, 0, 0, 0, 0],
1194 [0, 0, 0, 0, 1, 0, 0, 0],
1195 [0, 0, 0, 0, 0, 1, 0, 0],
1196 [0, 0, 0, 0, 0, 0, 0, 1],
1197 [0, 0, 0, 0, 0, 0, 1, 0],
1198 ],
1199 dtype=complex,
1200 )
1202 @staticmethod
1203 @circuit.subroutine(register=True)
1204 def ccnot(control1: QubitInput, control2: QubitInput, target: QubitInput) -> Instruction:
1205 """Registers this function into the circuit class.
1207 Args:
1208 control1 (Qubit or int): Control qubit 1 index.
1209 control2 (Qubit or int): Control qubit 2 index.
1210 target (Qubit or int): Target qubit index.
1212 Returns:
1213 Instruction: CCNot instruction.
1215 Examples:
1216 >>> circ = Circuit().ccnot(0, 1, 2)
1217 """
1218 return Instruction(Gate.CCNot(), target=[control1, control2, target])
1221Gate.register_gate(CCNot)
1224class CSwap(Gate):
1225 """Controlled Swap gate."""
1227 def __init__(self):
1228 super().__init__(qubit_count=3, ascii_symbols=["C", "SWAP", "SWAP"])
1230 def to_ir(self, target: QubitSet):
1231 return ir.CSwap.construct(control=target[0], targets=[target[1], target[2]])
1233 def to_matrix(self) -> np.ndarray:
1234 return np.array(
1235 [
1236 [1, 0, 0, 0, 0, 0, 0, 0],
1237 [0, 1, 0, 0, 0, 0, 0, 0],
1238 [0, 0, 1, 0, 0, 0, 0, 0],
1239 [0, 0, 0, 1, 0, 0, 0, 0],
1240 [0, 0, 0, 0, 1, 0, 0, 0],
1241 [0, 0, 0, 0, 0, 0, 1, 0],
1242 [0, 0, 0, 0, 0, 1, 0, 0],
1243 [0, 0, 0, 0, 0, 0, 0, 1],
1244 ],
1245 dtype=complex,
1246 )
1248 @staticmethod
1249 @circuit.subroutine(register=True)
1250 def cswap(control: QubitInput, target1: QubitInput, target2: QubitInput) -> Instruction:
1251 """Registers this function into the circuit class.
1253 Args:
1254 control (Qubit or int): Control qubit index
1255 target1 (Qubit or int): Target qubit 1 index.
1256 target2 (Qubit or int): Target qubit 2 index.
1258 Returns:
1259 Instruction: CSwap instruction.
1261 Examples:
1262 >>> circ = Circuit().cswap(0, 1, 2)
1263 """
1264 return Instruction(Gate.CSwap(), target=[control, target1, target2])
1267Gate.register_gate(CSwap)
1270class Unitary(Gate):
1271 """Arbitrary unitary gate
1273 Args:
1274 matrix (numpy.ndarray): Unitary matrix which defines the gate.
1275 display_name (str): Name to be used for an instance of this unitary gate
1276 for circuit diagrams. Defaults to `U`.
1278 Raises:
1279 ValueError: If `matrix` is not a two-dimensional square matrix,
1280 or has a dimension length which is not a positive exponent of 2,
1281 or is non-unitary.
1282 """
1284 def __init__(self, matrix: np.ndarray, display_name: str = "U"):
1285 verify_quantum_operator_matrix_dimensions(matrix)
1286 self._matrix = np.array(matrix, dtype=complex)
1287 qubit_count = int(np.log2(self._matrix.shape[0]))
1289 if not is_unitary(self._matrix):
1290 raise ValueError(f"{self._matrix} is not unitary")
1292 super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count)
1294 def to_matrix(self):
1295 return np.array(self._matrix)
1297 def to_ir(self, target: QubitSet):
1298 return ir.Unitary.construct(
1299 targets=[qubit for qubit in target],
1300 matrix=Unitary._transform_matrix_to_ir(self._matrix),
1301 )
1303 @staticmethod
1304 def _transform_matrix_to_ir(matrix: np.ndarray):
1305 return [[[element.real, element.imag] for element in row] for row in matrix.tolist()]
1307 @staticmethod
1308 @circuit.subroutine(register=True)
1309 def unitary(targets: QubitSet, matrix: np.ndarray, display_name: str = "U") -> Instruction:
1310 """Registers this function into the circuit class.
1312 Args:
1313 targets (QubitSet): Target qubits.
1314 matrix (numpy.ndarray): Unitary matrix which defines the gate. Matrix should be
1315 compatible with the supplied targets, with 2 ** len(targets) == matrix.shape[0].
1316 display_name (str): Name to be used for an instance of this unitary gate
1317 for circuit diagrams. Defaults to `U`.
1319 Returns:
1320 Instruction: Unitary instruction.
1322 Raises:
1323 ValueError: If `matrix` is not a two-dimensional square matrix,
1324 or has a dimension length which is not compatible with the `targets`,
1325 or is non-unitary,
1327 Examples:
1328 >>> circ = Circuit().unitary(matrix=np.array([[0, 1],[1, 0]]), targets=[0])
1329 """
1330 if 2 ** len(targets) != matrix.shape[0]: 1330 ↛ 1331line 1330 didn't jump to line 1331, because the condition on line 1330 was never true
1331 raise ValueError("Dimensions of the supplied unitary are incompatible with the targets")
1333 return Instruction(Gate.Unitary(matrix, display_name), target=targets)
1336Gate.register_gate(Unitary)