Hide keyboard shortcuts

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. 

13 

14import math 

15from typing import Iterable 

16 

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 

29 

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""" 

38 

39# Single qubit gates # 

40 

41 

42class H(Gate): 

43 """Hadamard gate.""" 

44 

45 def __init__(self): 

46 super().__init__(qubit_count=1, ascii_symbols=["H"]) 

47 

48 def to_ir(self, target: QubitSet): 

49 return ir.H.construct(target=target[0]) 

50 

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) 

53 

54 @staticmethod 

55 @circuit.subroutine(register=True) 

56 def h(target: QubitSetInput) -> Iterable[Instruction]: 

57 """Registers this function into the circuit class. 

58 

59 Args: 

60 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

61 

62 Returns: 

63 Iterable[Instruction]: `Iterable` of H instructions. 

64 

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)] 

70 

71 

72Gate.register_gate(H) 

73 

74 

75class I(Gate): # noqa: E742, E261 

76 """Identity gate.""" 

77 

78 def __init__(self): 

79 super().__init__(qubit_count=1, ascii_symbols=["I"]) 

80 

81 def to_ir(self, target: QubitSet): 

82 return ir.I.construct(target=target[0]) 

83 

84 def to_matrix(self) -> np.ndarray: 

85 return np.array([[1.0, 0.0], [0.0, 1.0]], dtype=complex) 

86 

87 @staticmethod 

88 @circuit.subroutine(register=True) 

89 def i(target: QubitSetInput) -> Iterable[Instruction]: 

90 """Registers this function into the circuit class. 

91 

92 Args: 

93 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

94 

95 Returns: 

96 Iterable[Instruction]: `Iterable` of I instructions. 

97 

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)] 

103 

104 

105Gate.register_gate(I) 

106 

107 

108class X(Gate): 

109 """Pauli-X gate.""" 

110 

111 def __init__(self): 

112 super().__init__(qubit_count=1, ascii_symbols=["X"]) 

113 

114 def to_ir(self, target: QubitSet): 

115 return ir.X.construct(target=target[0]) 

116 

117 def to_matrix(self) -> np.ndarray: 

118 return np.array([[0.0, 1.0], [1.0, 0.0]], dtype=complex) 

119 

120 @staticmethod 

121 @circuit.subroutine(register=True) 

122 def x(target: QubitSetInput) -> Iterable[Instruction]: 

123 """Registers this function into the circuit class. 

124 

125 Args: 

126 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

127 

128 Returns: 

129 Iterable[Instruction]: `Iterable` of X instructions. 

130 

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)] 

136 

137 

138Gate.register_gate(X) 

139 

140 

141class Y(Gate): 

142 """Pauli-Y gate.""" 

143 

144 def __init__(self): 

145 super().__init__(qubit_count=1, ascii_symbols=["Y"]) 

146 

147 def to_ir(self, target: QubitSet): 

148 return ir.Y.construct(target=target[0]) 

149 

150 def to_matrix(self) -> np.ndarray: 

151 return np.array([[0.0, -1.0j], [1.0j, 0.0]], dtype=complex) 

152 

153 @staticmethod 

154 @circuit.subroutine(register=True) 

155 def y(target: QubitSetInput) -> Iterable[Instruction]: 

156 """Registers this function into the circuit class. 

157 

158 Args: 

159 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

160 

161 Returns: 

162 Iterable[Instruction]: `Iterable` of Y instructions. 

163 

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)] 

169 

170 

171Gate.register_gate(Y) 

172 

173 

174class Z(Gate): 

175 """Pauli-Z gate.""" 

176 

177 def __init__(self): 

178 super().__init__(qubit_count=1, ascii_symbols=["Z"]) 

179 

180 def to_ir(self, target: QubitSet): 

181 return ir.Z.construct(target=target[0]) 

182 

183 def to_matrix(self) -> np.ndarray: 

184 return np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex) 

185 

186 @staticmethod 

187 @circuit.subroutine(register=True) 

188 def z(target: QubitSetInput) -> Iterable[Instruction]: 

189 """Registers this function into the circuit class. 

190 

191 Args: 

192 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

193 

194 Returns: 

195 Iterable[Instruction]: `Iterable` of Z instructions. 

196 

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)] 

202 

203 

204Gate.register_gate(Z) 

205 

206 

207class S(Gate): 

208 """S gate.""" 

209 

210 def __init__(self): 

211 super().__init__(qubit_count=1, ascii_symbols=["S"]) 

212 

213 def to_ir(self, target: QubitSet): 

214 return ir.S.construct(target=target[0]) 

215 

216 def to_matrix(self) -> np.ndarray: 

217 

218 return np.array([[1.0, 0.0], [0.0, 1.0j]], dtype=complex) 

219 

220 @staticmethod 

221 @circuit.subroutine(register=True) 

222 def s(target: QubitSetInput) -> Iterable[Instruction]: 

223 """Registers this function into the circuit class. 

224 

225 Args: 

226 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

227 

228 Returns: 

229 Iterable[Instruction]: `Iterable` of S instructions. 

230 

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)] 

236 

237 

238Gate.register_gate(S) 

239 

240 

241class Si(Gate): 

242 """Conjugate transpose of S gate.""" 

243 

244 def __init__(self): 

245 super().__init__(qubit_count=1, ascii_symbols=["Si"]) 

246 

247 def to_ir(self, target: QubitSet): 

248 return ir.Si.construct(target=target[0]) 

249 

250 def to_matrix(self) -> np.ndarray: 

251 return np.array([[1, 0], [0, -1j]], dtype=complex) 

252 

253 @staticmethod 

254 @circuit.subroutine(register=True) 

255 def si(target: QubitSetInput) -> Iterable[Instruction]: 

256 """Registers this function into the circuit class. 

257 

258 Args: 

259 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

260 

261 Returns: 

262 Iterable[Instruction]: Iterable of Si instructions. 

263 

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)] 

269 

270 

271Gate.register_gate(Si) 

272 

273 

274class T(Gate): 

275 """T gate.""" 

276 

277 def __init__(self): 

278 super().__init__(qubit_count=1, ascii_symbols=["T"]) 

279 

280 def to_ir(self, target: QubitSet): 

281 return ir.T.construct(target=target[0]) 

282 

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) 

285 

286 @staticmethod 

287 @circuit.subroutine(register=True) 

288 def t(target: QubitSetInput) -> Iterable[Instruction]: 

289 """Registers this function into the circuit class. 

290 

291 Args: 

292 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

293 

294 Returns: 

295 Iterable[Instruction]: `Iterable` of T instructions. 

296 

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)] 

302 

303 

304Gate.register_gate(T) 

305 

306 

307class Ti(Gate): 

308 """Conjugate transpose of T gate.""" 

309 

310 def __init__(self): 

311 super().__init__(qubit_count=1, ascii_symbols=["Ti"]) 

312 

313 def to_ir(self, target: QubitSet): 

314 return ir.Ti.construct(target=target[0]) 

315 

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) 

318 

319 @staticmethod 

320 @circuit.subroutine(register=True) 

321 def ti(target: QubitSetInput) -> Iterable[Instruction]: 

322 """Registers this function into the circuit class. 

323 

324 Args: 

325 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

326 

327 Returns: 

328 Iterable[Instruction]: `Iterable` of Ti instructions. 

329 

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)] 

335 

336 

337Gate.register_gate(Ti) 

338 

339 

340class V(Gate): 

341 """Square root of not gate.""" 

342 

343 def __init__(self): 

344 super().__init__(qubit_count=1, ascii_symbols=["V"]) 

345 

346 def to_ir(self, target: QubitSet): 

347 return ir.V.construct(target=target[0]) 

348 

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) 

351 

352 @staticmethod 

353 @circuit.subroutine(register=True) 

354 def v(target: QubitSetInput) -> Iterable[Instruction]: 

355 """Registers this function into the circuit class. 

356 

357 Args: 

358 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

359 

360 Returns: 

361 Iterable[Instruction]: `Iterable` of V instructions. 

362 

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)] 

368 

369 

370Gate.register_gate(V) 

371 

372 

373class Vi(Gate): 

374 """Conjugate transpose of square root of not gate.""" 

375 

376 def __init__(self): 

377 super().__init__(qubit_count=1, ascii_symbols=["Vi"]) 

378 

379 def to_ir(self, target: QubitSet): 

380 return ir.Vi.construct(target=target[0]) 

381 

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) 

384 

385 @staticmethod 

386 @circuit.subroutine(register=True) 

387 def vi(target: QubitSetInput) -> Iterable[Instruction]: 

388 """Registers this function into the circuit class. 

389 

390 Args: 

391 target (Qubit, int, or iterable of Qubit / int): Target qubit(s) 

392 

393 Returns: 

394 Iterable[Instruction]: `Iterable` of Vi instructions. 

395 

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)] 

401 

402 

403Gate.register_gate(Vi) 

404 

405 

406# Single qubit gates with rotation # 

407 

408 

409class Rx(AngledGate): 

410 """X-axis rotation gate. 

411 

412 Args: 

413 angle (float): angle in radians. 

414 """ 

415 

416 def __init__(self, angle: float): 

417 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rx({:.3g})".format(angle)]) 

418 

419 def to_ir(self, target: QubitSet): 

420 return ir.Rx.construct(target=target[0], angle=self.angle) 

421 

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) 

426 

427 @staticmethod 

428 @circuit.subroutine(register=True) 

429 def rx(target: QubitInput, angle: float) -> Instruction: 

430 """Registers this function into the circuit class. 

431 

432 Args: 

433 target (Qubit or int): Target qubit index. 

434 angle (float): Angle in radians. 

435 

436 Returns: 

437 Instruction: Rx instruction. 

438 

439 Examples: 

440 >>> circ = Circuit().rx(0, 0.15) 

441 """ 

442 return [Instruction(Gate.Rx(angle), target=qubit) for qubit in QubitSet(target)] 

443 

444 

445Gate.register_gate(Rx) 

446 

447 

448class Ry(AngledGate): 

449 """Y-axis rotation gate. 

450 

451 Args: 

452 angle (float): angle in radians. 

453 """ 

454 

455 def __init__(self, angle: float): 

456 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Ry({:.3g})".format(angle)]) 

457 

458 def to_ir(self, target: QubitSet): 

459 return ir.Ry.construct(target=target[0], angle=self.angle) 

460 

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) 

465 

466 @staticmethod 

467 @circuit.subroutine(register=True) 

468 def ry(target: QubitInput, angle: float) -> Instruction: 

469 """Registers this function into the circuit class. 

470 

471 Args: 

472 target (Qubit or int): Target qubit index. 

473 angle (float): Angle in radians. 

474 

475 Returns: 

476 Instruction: Ry instruction. 

477 

478 Examples: 

479 >>> circ = Circuit().ry(0, 0.15) 

480 """ 

481 return [Instruction(Gate.Ry(angle), target=qubit) for qubit in QubitSet(target)] 

482 

483 

484Gate.register_gate(Ry) 

485 

486 

487class Rz(AngledGate): 

488 """Z-axis rotation gate. 

489 

490 Args: 

491 angle (float): angle in radians. 

492 """ 

493 

494 def __init__(self, angle: float): 

495 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["Rz({:.3g})".format(angle)]) 

496 

497 def to_ir(self, target: QubitSet): 

498 return ir.Rz.construct(target=target[0], angle=self.angle) 

499 

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 ) 

504 

505 @staticmethod 

506 @circuit.subroutine(register=True) 

507 def rz(target: QubitInput, angle: float) -> Instruction: 

508 """Registers this function into the circuit class. 

509 

510 Args: 

511 target (Qubit or int): Target qubit index. 

512 angle (float): Angle in radians. 

513 

514 Returns: 

515 Instruction: Rz instruction. 

516 

517 Examples: 

518 >>> circ = Circuit().rz(0, 0.15) 

519 """ 

520 return [Instruction(Gate.Rz(angle), target=qubit) for qubit in QubitSet(target)] 

521 

522 

523Gate.register_gate(Rz) 

524 

525 

526class PhaseShift(AngledGate): 

527 """Phase shift gate. 

528 

529 Args: 

530 angle (float): angle in radians. 

531 """ 

532 

533 def __init__(self, angle: float): 

534 super().__init__(angle=angle, qubit_count=1, ascii_symbols=["PHASE({:.3g})".format(angle)]) 

535 

536 def to_ir(self, target: QubitSet): 

537 return ir.PhaseShift.construct(target=target[0], angle=self.angle) 

538 

539 def to_matrix(self) -> np.ndarray: 

540 return np.array([[1.0, 0.0], [0.0, np.exp(1j * self.angle)]], dtype=complex) 

541 

542 @staticmethod 

543 @circuit.subroutine(register=True) 

544 def phaseshift(target: QubitInput, angle: float) -> Instruction: 

545 """Registers this function into the circuit class. 

546 

547 Args: 

548 target (Qubit or int): Target qubit index. 

549 angle (float): Angle in radians. 

550 

551 Returns: 

552 Instruction: PhaseShift instruction. 

553 

554 Examples: 

555 >>> circ = Circuit().phaseshift(0, 0.15) 

556 """ 

557 return [Instruction(Gate.PhaseShift(angle), target=qubit) for qubit in QubitSet(target)] 

558 

559 

560Gate.register_gate(PhaseShift) 

561 

562 

563# Two qubit gates # 

564 

565 

566class CNot(Gate): 

567 """Controlled NOT gate.""" 

568 

569 def __init__(self): 

570 super().__init__(qubit_count=2, ascii_symbols=["C", "X"]) 

571 

572 def to_ir(self, target: QubitSet): 

573 return ir.CNot.construct(control=target[0], target=target[1]) 

574 

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 ) 

585 

586 @staticmethod 

587 @circuit.subroutine(register=True) 

588 def cnot(control: QubitInput, target: QubitInput) -> Instruction: 

589 """Registers this function into the circuit class. 

590 

591 Args: 

592 control (Qubit or int): Control qubit index. 

593 target (Qubit or int): Target qubit index. 

594 

595 Returns: 

596 Instruction: CNot instruction. 

597 

598 Examples: 

599 >>> circ = Circuit().cnot(0, 1) 

600 """ 

601 return Instruction(Gate.CNot(), target=[control, target]) 

602 

603 

604Gate.register_gate(CNot) 

605 

606 

607class Swap(Gate): 

608 """Swap gate.""" 

609 

610 def __init__(self): 

611 super().__init__(qubit_count=2, ascii_symbols=["SWAP", "SWAP"]) 

612 

613 def to_ir(self, target: QubitSet): 

614 return ir.Swap.construct(targets=[target[0], target[1]]) 

615 

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 ) 

626 

627 @staticmethod 

628 @circuit.subroutine(register=True) 

629 def swap(target1: QubitInput, target2: QubitInput) -> Instruction: 

630 """Registers this function into the circuit class. 

631 

632 Args: 

633 target1 (Qubit or int): Target qubit 1 index. 

634 target2 (Qubit or int): Target qubit 2 index. 

635 

636 Returns: 

637 Instruction: Swap instruction. 

638 

639 Examples: 

640 >>> circ = Circuit().swap(0, 1) 

641 """ 

642 return Instruction(Gate.Swap(), target=[target1, target2]) 

643 

644 

645Gate.register_gate(Swap) 

646 

647 

648class ISwap(Gate): 

649 """ISwap gate.""" 

650 

651 def __init__(self): 

652 super().__init__(qubit_count=2, ascii_symbols=["ISWAP", "ISWAP"]) 

653 

654 def to_ir(self, target: QubitSet): 

655 return ir.ISwap.construct(targets=[target[0], target[1]]) 

656 

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 ) 

667 

668 @staticmethod 

669 @circuit.subroutine(register=True) 

670 def iswap(target1: QubitInput, target2: QubitInput) -> Instruction: 

671 """Registers this function into the circuit class. 

672 

673 Args: 

674 target1 (Qubit or int): Target qubit 1 index. 

675 target2 (Qubit or int): Target qubit 2 index. 

676 

677 Returns: 

678 Instruction: ISwap instruction. 

679 

680 Examples: 

681 >>> circ = Circuit().iswap(0, 1) 

682 """ 

683 return Instruction(Gate.ISwap(), target=[target1, target2]) 

684 

685 

686Gate.register_gate(ISwap) 

687 

688 

689class PSwap(AngledGate): 

690 """PSwap gate. 

691 

692 Args: 

693 angle (float): angle in radians. 

694 """ 

695 

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 ) 

702 

703 def to_ir(self, target: QubitSet): 

704 return ir.PSwap.construct(targets=[target[0], target[1]], angle=self.angle) 

705 

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 ) 

716 

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. 

721 

722 Args: 

723 target1 (Qubit or int): Target qubit 1 index. 

724 target2 (Qubit or int): Target qubit 2 index. 

725 

726 Returns: 

727 Instruction: PSwap instruction. 

728 

729 Examples: 

730 >>> circ = Circuit().pswap(0, 1, 0.15) 

731 """ 

732 return Instruction(Gate.PSwap(angle), target=[target1, target2]) 

733 

734 

735Gate.register_gate(PSwap) 

736 

737 

738class XY(AngledGate): 

739 """XY gate. 

740 

741 Args: 

742 angle (float): angle in radians. 

743 """ 

744 

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 ) 

751 

752 def to_ir(self, target: QubitSet): 

753 return ir.XY.construct(targets=[target[0], target[1]], angle=self.angle) 

754 

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 ) 

767 

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. 

772 

773 Args: 

774 target1 (Qubit or int): Target qubit 1 index. 

775 target2 (Qubit or int): Target qubit 2 index. 

776 

777 Returns: 

778 Instruction: XY instruction. 

779 

780 Examples: 

781 >>> circ = Circuit().xy(0, 1, 0.15) 

782 """ 

783 return Instruction(Gate.XY(angle), target=[target1, target2]) 

784 

785 

786Gate.register_gate(XY) 

787 

788 

789class CPhaseShift(AngledGate): 

790 """Controlled phase shift gate. 

791 

792 Args: 

793 angle (float): angle in radians. 

794 """ 

795 

796 def __init__(self, angle: float): 

797 super().__init__( 

798 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE({:.3g})".format(angle)] 

799 ) 

800 

801 def to_ir(self, target: QubitSet): 

802 return ir.CPhaseShift.construct(control=target[0], target=target[1], angle=self.angle) 

803 

804 def to_matrix(self) -> np.ndarray: 

805 return np.diag([1.0, 1.0, 1.0, np.exp(1j * self.angle)]) 

806 

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. 

811 

812 Args: 

813 control (Qubit or int): Control qubit index. 

814 target (Qubit or int): Target qubit index. 

815 angle (float): Angle in radians. 

816 

817 Returns: 

818 Instruction: CPhaseShift instruction. 

819 

820 Examples: 

821 >>> circ = Circuit().cphaseshift(0, 1, 0.15) 

822 """ 

823 return Instruction(Gate.CPhaseShift(angle), target=[control, target]) 

824 

825 

826Gate.register_gate(CPhaseShift) 

827 

828 

829class CPhaseShift00(AngledGate): 

830 """Controlled phase shift gate for phasing the \\|00> state. 

831 

832 Args: 

833 angle (float): angle in radians. 

834 """ 

835 

836 def __init__(self, angle: float): 

837 super().__init__( 

838 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE00({:.3g})".format(angle)] 

839 ) 

840 

841 def to_ir(self, target: QubitSet): 

842 return ir.CPhaseShift00.construct(control=target[0], target=target[1], angle=self.angle) 

843 

844 def to_matrix(self) -> np.ndarray: 

845 return np.diag([np.exp(1j * self.angle), 1.0, 1.0, 1.0]) 

846 

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. 

851 

852 Args: 

853 control (Qubit or int): Control qubit index. 

854 target (Qubit or int): Target qubit index. 

855 angle (float): Angle in radians. 

856 

857 Returns: 

858 Instruction: CPhaseShift00 instruction. 

859 

860 Examples: 

861 >>> circ = Circuit().cphaseshift00(0, 1, 0.15) 

862 """ 

863 return Instruction(Gate.CPhaseShift00(angle), target=[control, target]) 

864 

865 

866Gate.register_gate(CPhaseShift00) 

867 

868 

869class CPhaseShift01(AngledGate): 

870 """Controlled phase shift gate for phasing the \\|01> state. 

871 

872 Args: 

873 angle (float): angle in radians. 

874 """ 

875 

876 def __init__(self, angle: float): 

877 super().__init__( 

878 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE01({:.3g})".format(angle)] 

879 ) 

880 

881 def to_ir(self, target: QubitSet): 

882 return ir.CPhaseShift01.construct(control=target[0], target=target[1], angle=self.angle) 

883 

884 def to_matrix(self) -> np.ndarray: 

885 return np.diag([1.0, np.exp(1j * self.angle), 1.0, 1.0]) 

886 

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. 

891 

892 Args: 

893 control (Qubit or int): Control qubit index. 

894 target (Qubit or int): Target qubit index. 

895 angle (float): Angle in radians. 

896 

897 Returns: 

898 Instruction: CPhaseShift01 instruction. 

899 

900 Examples: 

901 >>> circ = Circuit().cphaseshift01(0, 1, 0.15) 

902 """ 

903 return Instruction(Gate.CPhaseShift01(angle), target=[control, target]) 

904 

905 

906Gate.register_gate(CPhaseShift01) 

907 

908 

909class CPhaseShift10(AngledGate): 

910 """Controlled phase shift gate for phasing the \\|10> state. 

911 

912 Args: 

913 angle (float): angle in radians. 

914 """ 

915 

916 def __init__(self, angle: float): 

917 super().__init__( 

918 angle=angle, qubit_count=2, ascii_symbols=["C", "PHASE10({:.3g})".format(angle)] 

919 ) 

920 

921 def to_ir(self, target: QubitSet): 

922 return ir.CPhaseShift10.construct(control=target[0], target=target[1], angle=self.angle) 

923 

924 def to_matrix(self) -> np.ndarray: 

925 return np.diag([1.0, 1.0, np.exp(1j * self.angle), 1.0]) 

926 

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. 

931 

932 Args: 

933 control (Qubit or int): Control qubit index. 

934 target (Qubit or int): Target qubit index. 

935 angle (float): Angle in radians. 

936 

937 Returns: 

938 Instruction: CPhaseShift10 instruction. 

939 

940 Examples: 

941 >>> circ = Circuit().cphaseshift10(0, 1, 0.15) 

942 """ 

943 return Instruction(Gate.CPhaseShift10(angle), target=[control, target]) 

944 

945 

946Gate.register_gate(CPhaseShift10) 

947 

948 

949class CY(Gate): 

950 """Controlled Pauli-Y gate.""" 

951 

952 def __init__(self): 

953 super().__init__(qubit_count=2, ascii_symbols=["C", "Y"]) 

954 

955 def to_ir(self, target: QubitSet): 

956 return ir.CY.construct(control=target[0], target=target[1]) 

957 

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 ) 

968 

969 @staticmethod 

970 @circuit.subroutine(register=True) 

971 def cy(control: QubitInput, target: QubitInput) -> Instruction: 

972 """Registers this function into the circuit class. 

973 

974 Args: 

975 control (Qubit or int): Control qubit index. 

976 target (Qubit or int): Target qubit index. 

977 

978 Returns: 

979 Instruction: CY instruction. 

980 

981 Examples: 

982 >>> circ = Circuit().cy(0, 1) 

983 """ 

984 return Instruction(Gate.CY(), target=[control, target]) 

985 

986 

987Gate.register_gate(CY) 

988 

989 

990class CZ(Gate): 

991 """Controlled Pauli-Z gate.""" 

992 

993 def __init__(self): 

994 super().__init__(qubit_count=2, ascii_symbols=["C", "Z"]) 

995 

996 def to_ir(self, target: QubitSet): 

997 return ir.CZ.construct(control=target[0], target=target[1]) 

998 

999 def to_matrix(self) -> np.ndarray: 

1000 return np.diag([1.0, 1.0, 1.0, -1.0]) 

1001 

1002 @staticmethod 

1003 @circuit.subroutine(register=True) 

1004 def cz(control: QubitInput, target: QubitInput) -> Instruction: 

1005 """Registers this function into the circuit class. 

1006 

1007 Args: 

1008 control (Qubit or int): Control qubit index. 

1009 target (Qubit or int): Target qubit index. 

1010 

1011 Returns: 

1012 Instruction: CZ instruction. 

1013 

1014 Examples: 

1015 >>> circ = Circuit().cz(0, 1) 

1016 """ 

1017 return Instruction(Gate.CZ(), target=[control, target]) 

1018 

1019 

1020Gate.register_gate(CZ) 

1021 

1022 

1023class XX(AngledGate): 

1024 """Ising XX coupling gate. 

1025 

1026 Args: 

1027 angle (float): angle in radians. 

1028 """ 

1029 

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 ) 

1036 

1037 def to_ir(self, target: QubitSet): 

1038 return ir.XX.construct(targets=[target[0], target[1]], angle=self.angle) 

1039 

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 ) 

1050 

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. 

1055 

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. 

1060 

1061 Returns: 

1062 Instruction: XX instruction. 

1063 

1064 Examples: 

1065 >>> circ = Circuit().xx(0, 1, 0.15) 

1066 """ 

1067 return Instruction(Gate.XX(angle), target=[target1, target2]) 

1068 

1069 

1070Gate.register_gate(XX) 

1071 

1072 

1073class YY(AngledGate): 

1074 """Ising YY coupling gate. 

1075 

1076 Args: 

1077 angle (float): angle in radians. 

1078 """ 

1079 

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 ) 

1086 

1087 def to_ir(self, target: QubitSet): 

1088 return ir.YY.construct(targets=[target[0], target[1]], angle=self.angle) 

1089 

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 ) 

1102 

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. 

1107 

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. 

1112 

1113 Returns: 

1114 Instruction: YY instruction. 

1115 

1116 Examples: 

1117 >>> circ = Circuit().yy(0, 1, 0.15) 

1118 """ 

1119 return Instruction(Gate.YY(angle), target=[target1, target2]) 

1120 

1121 

1122Gate.register_gate(YY) 

1123 

1124 

1125class ZZ(AngledGate): 

1126 """Ising ZZ coupling gate. 

1127 

1128 Args: 

1129 angle (float): angle in radians. 

1130 """ 

1131 

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 ) 

1138 

1139 def to_ir(self, target: QubitSet): 

1140 return ir.ZZ.construct(targets=[target[0], target[1]], angle=self.angle) 

1141 

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 ) 

1152 

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. 

1157 

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. 

1162 

1163 Returns: 

1164 Instruction: ZZ instruction. 

1165 

1166 Examples: 

1167 >>> circ = Circuit().zz(0, 1, 0.15) 

1168 """ 

1169 return Instruction(Gate.ZZ(angle), target=[target1, target2]) 

1170 

1171 

1172Gate.register_gate(ZZ) 

1173 

1174 

1175# Three qubit gates # 

1176 

1177 

1178class CCNot(Gate): 

1179 """CCNOT gate or Toffoli gate.""" 

1180 

1181 def __init__(self): 

1182 super().__init__(qubit_count=3, ascii_symbols=["C", "C", "X"]) 

1183 

1184 def to_ir(self, target: QubitSet): 

1185 return ir.CCNot.construct(controls=[target[0], target[1]], target=target[2]) 

1186 

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 ) 

1201 

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. 

1206 

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. 

1211 

1212 Returns: 

1213 Instruction: CCNot instruction. 

1214 

1215 Examples: 

1216 >>> circ = Circuit().ccnot(0, 1, 2) 

1217 """ 

1218 return Instruction(Gate.CCNot(), target=[control1, control2, target]) 

1219 

1220 

1221Gate.register_gate(CCNot) 

1222 

1223 

1224class CSwap(Gate): 

1225 """Controlled Swap gate.""" 

1226 

1227 def __init__(self): 

1228 super().__init__(qubit_count=3, ascii_symbols=["C", "SWAP", "SWAP"]) 

1229 

1230 def to_ir(self, target: QubitSet): 

1231 return ir.CSwap.construct(control=target[0], targets=[target[1], target[2]]) 

1232 

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 ) 

1247 

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. 

1252 

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. 

1257 

1258 Returns: 

1259 Instruction: CSwap instruction. 

1260 

1261 Examples: 

1262 >>> circ = Circuit().cswap(0, 1, 2) 

1263 """ 

1264 return Instruction(Gate.CSwap(), target=[control, target1, target2]) 

1265 

1266 

1267Gate.register_gate(CSwap) 

1268 

1269 

1270class Unitary(Gate): 

1271 """Arbitrary unitary gate 

1272 

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`. 

1277 

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 """ 

1283 

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])) 

1288 

1289 if not is_unitary(self._matrix): 

1290 raise ValueError(f"{self._matrix} is not unitary") 

1291 

1292 super().__init__(qubit_count=qubit_count, ascii_symbols=[display_name] * qubit_count) 

1293 

1294 def to_matrix(self): 

1295 return np.array(self._matrix) 

1296 

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 ) 

1302 

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()] 

1306 

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. 

1311 

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`. 

1318 

1319 Returns: 

1320 Instruction: Unitary instruction. 

1321 

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, 

1326 

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") 

1332 

1333 return Instruction(Gate.Unitary(matrix, display_name), target=targets) 

1334 

1335 

1336Gate.register_gate(Unitary)