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 

14from typing import Iterable 

15 

16import braket.ir.jaqcd as ir 

17import numpy as np 

18from braket.circuits import circuit 

19from braket.circuits.angled_gate import AngledGate 

20from braket.circuits.gate import Gate 

21from braket.circuits.instruction import Instruction 

22from braket.circuits.quantum_operator_helpers import ( 

23 is_unitary, 

24 verify_quantum_operator_matrix_dimensions, 

25) 

26from braket.circuits.qubit import QubitInput 

27from braket.circuits.qubit_set import QubitSet, QubitSetInput 

28 

29""" 

30To add a new gate: 

31 1. Implement the class and extend `Gate` 

32 2. Add a method with the `@circuit.subroutine(register=True)` decorator. Method name 

33 will be added into the `Circuit` class. This method is the default way 

34 clients add this gate to a circuit. 

35 3. Register the class with the `Gate` class via `Gate.register_gate()`. 

36""" 

37 

38# Single qubit gates # 

39 

40 

41class H(Gate): 

42 """Hadamard gate.""" 

43 

44 def __init__(self): 

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

46 

47 def to_ir(self, target: QubitSet): 

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

49 

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

51 return 1.0 / np.sqrt(2.0) * np.array([[1.0, 1.0], [1.0, -1.0]], dtype=complex) 

52 

53 @staticmethod 

54 @circuit.subroutine(register=True) 

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

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

57 

58 Args: 

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

60 

61 Returns: 

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

63 

64 Examples: 

65 >>> circ = Circuit().h(0) 

66 >>> circ = Circuit().h([0, 1, 2]) 

67 """ 

68 return [Instruction(Gate.H(), target=qubit) for qubit in QubitSet(target)] 

69 

70 

71Gate.register_gate(H) 

72 

73 

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

75 """Identity gate.""" 

76 

77 def __init__(self): 

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

79 

80 def to_ir(self, target: QubitSet): 

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

82 

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

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

85 

86 @staticmethod 

87 @circuit.subroutine(register=True) 

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

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

90 

91 Args: 

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

93 

94 Returns: 

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

96 

97 Examples: 

98 >>> circ = Circuit().i(0) 

99 >>> circ = Circuit().i([0, 1, 2]) 

100 """ 

101 return [Instruction(Gate.I(), target=qubit) for qubit in QubitSet(target)] 

102 

103 

104Gate.register_gate(I) 

105 

106 

107class X(Gate): 

108 """Pauli-X gate.""" 

109 

110 def __init__(self): 

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

112 

113 def to_ir(self, target: QubitSet): 

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

115 

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

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

118 

119 @staticmethod 

120 @circuit.subroutine(register=True) 

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

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

123 

124 Args: 

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

126 

127 Returns: 

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

129 

130 Examples: 

131 >>> circ = Circuit().x(0) 

132 >>> circ = Circuit().x([0, 1, 2]) 

133 """ 

134 return [Instruction(Gate.X(), target=qubit) for qubit in QubitSet(target)] 

135 

136 

137Gate.register_gate(X) 

138 

139 

140class Y(Gate): 

141 """Pauli-Y gate.""" 

142 

143 def __init__(self): 

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

145 

146 def to_ir(self, target: QubitSet): 

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

148 

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

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

151 

152 @staticmethod 

153 @circuit.subroutine(register=True) 

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

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

156 

157 Args: 

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

159 

160 Returns: 

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

162 

163 Examples: 

164 >>> circ = Circuit().y(0) 

165 >>> circ = Circuit().y([0, 1, 2]) 

166 """ 

167 return [Instruction(Gate.Y(), target=qubit) for qubit in QubitSet(target)] 

168 

169 

170Gate.register_gate(Y) 

171 

172 

173class Z(Gate): 

174 """Pauli-Z gate.""" 

175 

176 def __init__(self): 

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

178 

179 def to_ir(self, target: QubitSet): 

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

181 

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

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

184 

185 @staticmethod 

186 @circuit.subroutine(register=True) 

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

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

189 

190 Args: 

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

192 

193 Returns: 

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

195 

196 Examples: 

197 >>> circ = Circuit().z(0) 

198 >>> circ = Circuit().z([0, 1, 2]) 

199 """ 

200 return [Instruction(Gate.Z(), target=qubit) for qubit in QubitSet(target)] 

201 

202 

203Gate.register_gate(Z) 

204 

205 

206class S(Gate): 

207 """S gate.""" 

208 

209 def __init__(self): 

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

211 

212 def to_ir(self, target: QubitSet): 

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

214 

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

216 

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

218 

219 @staticmethod 

220 @circuit.subroutine(register=True) 

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

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

223 

224 Args: 

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

226 

227 Returns: 

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

229 

230 Examples: 

231 >>> circ = Circuit().s(0) 

232 >>> circ = Circuit().s([0, 1, 2]) 

233 """ 

234 return [Instruction(Gate.S(), target=qubit) for qubit in QubitSet(target)] 

235 

236 

237Gate.register_gate(S) 

238 

239 

240class Si(Gate): 

241 """Conjugate transpose of S gate.""" 

242 

243 def __init__(self): 

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

245 

246 def to_ir(self, target: QubitSet): 

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

248 

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

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

251 

252 @staticmethod 

253 @circuit.subroutine(register=True) 

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

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

256 

257 Args: 

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

259 

260 Returns: 

261 Iterable[Instruction]: Iterable of Si instructions. 

262 

263 Examples: 

264 >>> circ = Circuit().si(0) 

265 >>> circ = Circuit().si([0, 1, 2]) 

266 """ 

267 return [Instruction(Gate.Si(), target=qubit) for qubit in QubitSet(target)] 

268 

269 

270Gate.register_gate(Si) 

271 

272 

273class T(Gate): 

274 """T gate.""" 

275 

276 def __init__(self): 

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

278 

279 def to_ir(self, target: QubitSet): 

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

281 

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

283 return np.array([[1.0, 0.0], [0.0, np.exp(1j * np.pi / 4)]], dtype=complex) 

284 

285 @staticmethod 

286 @circuit.subroutine(register=True) 

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

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

289 

290 Args: 

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

292 

293 Returns: 

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

295 

296 Examples: 

297 >>> circ = Circuit().t(0) 

298 >>> circ = Circuit().t([0, 1, 2]) 

299 """ 

300 return [Instruction(Gate.T(), target=qubit) for qubit in QubitSet(target)] 

301 

302 

303Gate.register_gate(T) 

304 

305 

306class Ti(Gate): 

307 """Conjugate transpose of T gate.""" 

308 

309 def __init__(self): 

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

311 

312 def to_ir(self, target: QubitSet): 

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

314 

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

316 return np.array([[1.0, 0.0], [0.0, np.exp(-1j * np.pi / 4)]], dtype=complex) 

317 

318 @staticmethod 

319 @circuit.subroutine(register=True) 

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

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

322 

323 Args: 

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

325 

326 Returns: 

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

328 

329 Examples: 

330 >>> circ = Circuit().ti(0) 

331 >>> circ = Circuit().ti([0, 1, 2]) 

332 """ 

333 return [Instruction(Gate.Ti(), target=qubit) for qubit in QubitSet(target)] 

334 

335 

336Gate.register_gate(Ti) 

337 

338 

339class V(Gate): 

340 """Square root of not gate.""" 

341 

342 def __init__(self): 

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

344 

345 def to_ir(self, target: QubitSet): 

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

347 

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

349 return np.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=complex) 

350 

351 @staticmethod 

352 @circuit.subroutine(register=True) 

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

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

355 

356 Args: 

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

358 

359 Returns: 

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

361 

362 Examples: 

363 >>> circ = Circuit().v(0) 

364 >>> circ = Circuit().v([0, 1, 2]) 

365 """ 

366 return [Instruction(Gate.V(), target=qubit) for qubit in QubitSet(target)] 

367 

368 

369Gate.register_gate(V) 

370 

371 

372class Vi(Gate): 

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

374 

375 def __init__(self): 

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

377 

378 def to_ir(self, target: QubitSet): 

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

380 

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

382 return np.array(([[0.5 - 0.5j, 0.5 + 0.5j], [0.5 + 0.5j, 0.5 - 0.5j]]), dtype=complex) 

383 

384 @staticmethod 

385 @circuit.subroutine(register=True) 

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

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

388 

389 Args: 

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

391 

392 Returns: 

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

394 

395 Examples: 

396 >>> circ = Circuit().vi(0) 

397 >>> circ = Circuit().vi([0, 1, 2]) 

398 """ 

399 return [Instruction(Gate.Vi(), target=qubit) for qubit in QubitSet(target)] 

400 

401 

402Gate.register_gate(Vi) 

403 

404 

405# Single qubit gates with rotation # 

406 

407 

408class Rx(AngledGate): 

409 """X-axis rotation gate. 

410 

411 Args: 

412 angle (float): angle in radians. 

413 """ 

414 

415 def __init__(self, angle: float): 

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

417 

418 def to_ir(self, target: QubitSet): 

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

420 

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

422 cos = np.cos(self.angle / 2) 

423 sin = np.sin(self.angle / 2) 

424 return np.array([[cos, -1j * sin], [-1j * sin, cos]], dtype=complex) 

425 

426 @staticmethod 

427 @circuit.subroutine(register=True) 

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

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

430 

431 Args: 

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

433 angle (float): Angle in radians. 

434 

435 Returns: 

436 Instruction: Rx instruction. 

437 

438 Examples: 

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

440 """ 

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

442 

443 

444Gate.register_gate(Rx) 

445 

446 

447class Ry(AngledGate): 

448 """Y-axis rotation gate. 

449 

450 Args: 

451 angle (float): angle in radians. 

452 """ 

453 

454 def __init__(self, angle: float): 

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

456 

457 def to_ir(self, target: QubitSet): 

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

459 

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

461 cos = np.cos(self.angle / 2) 

462 sin = np.sin(self.angle / 2) 

463 return np.array([[cos, -sin], [+sin, cos]], dtype=complex) 

464 

465 @staticmethod 

466 @circuit.subroutine(register=True) 

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

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

469 

470 Args: 

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

472 angle (float): Angle in radians. 

473 

474 Returns: 

475 Instruction: Ry instruction. 

476 

477 Examples: 

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

479 """ 

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

481 

482 

483Gate.register_gate(Ry) 

484 

485 

486class Rz(AngledGate): 

487 """Z-axis rotation gate. 

488 

489 Args: 

490 angle (float): angle in radians. 

491 """ 

492 

493 def __init__(self, angle: float): 

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

495 

496 def to_ir(self, target: QubitSet): 

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

498 

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

500 return np.array( 

501 [[np.exp(-1j * self.angle / 2), 0], [0, np.exp(1j * self.angle / 2)]], dtype=complex 

502 ) 

503 

504 @staticmethod 

505 @circuit.subroutine(register=True) 

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

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

508 

509 Args: 

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

511 angle (float): Angle in radians. 

512 

513 Returns: 

514 Instruction: Rz instruction. 

515 

516 Examples: 

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

518 """ 

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

520 

521 

522Gate.register_gate(Rz) 

523 

524 

525class PhaseShift(AngledGate): 

526 """Phase shift gate. 

527 

528 Args: 

529 angle (float): angle in radians. 

530 """ 

531 

532 def __init__(self, angle: float): 

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

534 

535 def to_ir(self, target: QubitSet): 

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

537 

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

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

540 

541 @staticmethod 

542 @circuit.subroutine(register=True) 

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

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

545 

546 Args: 

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

548 angle (float): Angle in radians. 

549 

550 Returns: 

551 Instruction: PhaseShift instruction. 

552 

553 Examples: 

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

555 """ 

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

557 

558 

559Gate.register_gate(PhaseShift) 

560 

561 

562# Two qubit gates # 

563 

564 

565class CNot(Gate): 

566 """Controlled NOT gate.""" 

567 

568 def __init__(self): 

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

570 

571 def to_ir(self, target: QubitSet): 

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

573 

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

575 return np.array( 

576 [ 

577 [1.0, 0.0, 0.0, 0.0], 

578 [0.0, 1.0, 0.0, 0.0], 

579 [0.0, 0.0, 0.0, 1.0], 

580 [0.0, 0.0, 1.0, 0.0], 

581 ], 

582 dtype=complex, 

583 ) 

584 

585 @staticmethod 

586 @circuit.subroutine(register=True) 

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

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

589 

590 Args: 

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

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

593 

594 Returns: 

595 Instruction: CNot instruction. 

596 

597 Examples: 

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

599 """ 

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

601 

602 

603Gate.register_gate(CNot) 

604 

605 

606class Swap(Gate): 

607 """Swap gate.""" 

608 

609 def __init__(self): 

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

611 

612 def to_ir(self, target: QubitSet): 

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

614 

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

616 return np.array( 

617 [ 

618 [1.0, 0.0, 0.0, 0.0], 

619 [0.0, 0.0, 1.0, 0.0], 

620 [0.0, 1.0, 0.0, 0.0], 

621 [0.0, 0.0, 0.0, 1.0], 

622 ], 

623 dtype=complex, 

624 ) 

625 

626 @staticmethod 

627 @circuit.subroutine(register=True) 

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

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

630 

631 Args: 

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

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

634 

635 Returns: 

636 Instruction: Swap instruction. 

637 

638 Examples: 

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

640 """ 

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

642 

643 

644Gate.register_gate(Swap) 

645 

646 

647class ISwap(Gate): 

648 """ISwap gate.""" 

649 

650 def __init__(self): 

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

652 

653 def to_ir(self, target: QubitSet): 

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

655 

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

657 return np.array( 

658 [ 

659 [1.0, 0.0, 0.0, 0.0], 

660 [0.0, 0.0, 1.0j, 0.0], 

661 [0.0, 1.0j, 0.0, 0.0], 

662 [0.0, 0.0, 0.0, 1.0], 

663 ], 

664 dtype=complex, 

665 ) 

666 

667 @staticmethod 

668 @circuit.subroutine(register=True) 

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

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

671 

672 Args: 

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

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

675 

676 Returns: 

677 Instruction: ISwap instruction. 

678 

679 Examples: 

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

681 """ 

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

683 

684 

685Gate.register_gate(ISwap) 

686 

687 

688class PSwap(AngledGate): 

689 """PSwap gate. 

690 

691 Args: 

692 angle (float): angle in radians. 

693 """ 

694 

695 def __init__(self, angle: float): 

696 super().__init__( 

697 angle=angle, 

698 qubit_count=2, 

699 ascii_symbols=["PSWAP({:.3g})".format(angle), "PSWAP({:.3g})".format(angle)], 

700 ) 

701 

702 def to_ir(self, target: QubitSet): 

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

704 

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

706 return np.array( 

707 [ 

708 [1.0, 0.0, 0.0, 0.0], 

709 [0.0, 0.0, np.exp(1j * self.angle), 0.0], 

710 [0.0, np.exp(1j * self.angle), 0.0, 0.0], 

711 [0.0, 0.0, 0.0, 1.0], 

712 ], 

713 dtype=complex, 

714 ) 

715 

716 @staticmethod 

717 @circuit.subroutine(register=True) 

718 def pswap(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction: 

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

720 

721 Args: 

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

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

724 

725 Returns: 

726 Instruction: PSwap instruction. 

727 

728 Examples: 

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

730 """ 

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

732 

733 

734Gate.register_gate(PSwap) 

735 

736 

737class XY(AngledGate): 

738 """XY gate. 

739 

740 Reference: https://arxiv.org/abs/1912.04424v1 

741 

742 Args: 

743 angle (float): angle in radians. 

744 """ 

745 

746 def __init__(self, angle: float): 

747 super().__init__( 

748 angle=angle, 

749 qubit_count=2, 

750 ascii_symbols=["XY({:.3g})".format(angle), "XY({:.3g})".format(angle)], 

751 ) 

752 

753 def to_ir(self, target: QubitSet): 

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

755 

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

757 cos = np.cos(self.angle / 2) 

758 sin = np.sin(self.angle / 2) 

759 return np.array( 

760 [ 

761 [1.0, 0.0, 0.0, 0.0], 

762 [0.0, cos, 1.0j * sin, 0.0], 

763 [0.0, 1.0j * sin, cos, 0.0], 

764 [0.0, 0.0, 0.0, 1.0], 

765 ], 

766 dtype=complex, 

767 ) 

768 

769 @staticmethod 

770 @circuit.subroutine(register=True) 

771 def xy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction: 

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

773 

774 Args: 

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

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

777 

778 Returns: 

779 Instruction: XY instruction. 

780 

781 Examples: 

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

783 """ 

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

785 

786 

787Gate.register_gate(XY) 

788 

789 

790class CPhaseShift(AngledGate): 

791 """Controlled phase shift gate. 

792 

793 Args: 

794 angle (float): angle in radians. 

795 """ 

796 

797 def __init__(self, angle: float): 

798 super().__init__( 

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

800 ) 

801 

802 def to_ir(self, target: QubitSet): 

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

804 

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

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

807 

808 @staticmethod 

809 @circuit.subroutine(register=True) 

810 def cphaseshift(control: QubitInput, target: QubitInput, angle: float) -> Instruction: 

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

812 

813 Args: 

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

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

816 angle (float): Angle in radians. 

817 

818 Returns: 

819 Instruction: CPhaseShift instruction. 

820 

821 Examples: 

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

823 """ 

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

825 

826 

827Gate.register_gate(CPhaseShift) 

828 

829 

830class CPhaseShift00(AngledGate): 

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

832 

833 Args: 

834 angle (float): angle in radians. 

835 """ 

836 

837 def __init__(self, angle: float): 

838 super().__init__( 

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

840 ) 

841 

842 def to_ir(self, target: QubitSet): 

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

844 

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

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

847 

848 @staticmethod 

849 @circuit.subroutine(register=True) 

850 def cphaseshift00(control: QubitInput, target: QubitInput, angle: float) -> Instruction: 

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

852 

853 Args: 

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

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

856 angle (float): Angle in radians. 

857 

858 Returns: 

859 Instruction: CPhaseShift00 instruction. 

860 

861 Examples: 

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

863 """ 

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

865 

866 

867Gate.register_gate(CPhaseShift00) 

868 

869 

870class CPhaseShift01(AngledGate): 

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

872 

873 Args: 

874 angle (float): angle in radians. 

875 """ 

876 

877 def __init__(self, angle: float): 

878 super().__init__( 

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

880 ) 

881 

882 def to_ir(self, target: QubitSet): 

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

884 

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

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

887 

888 @staticmethod 

889 @circuit.subroutine(register=True) 

890 def cphaseshift01(control: QubitInput, target: QubitInput, angle: float) -> Instruction: 

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

892 

893 Args: 

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

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

896 angle (float): Angle in radians. 

897 

898 Returns: 

899 Instruction: CPhaseShift01 instruction. 

900 

901 Examples: 

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

903 """ 

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

905 

906 

907Gate.register_gate(CPhaseShift01) 

908 

909 

910class CPhaseShift10(AngledGate): 

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

912 

913 Args: 

914 angle (float): angle in radians. 

915 """ 

916 

917 def __init__(self, angle: float): 

918 super().__init__( 

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

920 ) 

921 

922 def to_ir(self, target: QubitSet): 

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

924 

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

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

927 

928 @staticmethod 

929 @circuit.subroutine(register=True) 

930 def cphaseshift10(control: QubitInput, target: QubitInput, angle: float) -> Instruction: 

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

932 

933 Args: 

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

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

936 angle (float): Angle in radians. 

937 

938 Returns: 

939 Instruction: CPhaseShift10 instruction. 

940 

941 Examples: 

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

943 """ 

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

945 

946 

947Gate.register_gate(CPhaseShift10) 

948 

949 

950class CY(Gate): 

951 """Controlled Pauli-Y gate.""" 

952 

953 def __init__(self): 

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

955 

956 def to_ir(self, target: QubitSet): 

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

958 

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

960 return np.array( 

961 [ 

962 [1.0, 0.0, 0.0, 0.0], 

963 [0.0, 1.0, 0.0, 0.0], 

964 [0.0, 0.0, 0.0, -1.0j], 

965 [0.0, 0.0, +1.0j, 0.0], 

966 ], 

967 dtype=complex, 

968 ) 

969 

970 @staticmethod 

971 @circuit.subroutine(register=True) 

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

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

974 

975 Args: 

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

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

978 

979 Returns: 

980 Instruction: CY instruction. 

981 

982 Examples: 

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

984 """ 

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

986 

987 

988Gate.register_gate(CY) 

989 

990 

991class CZ(Gate): 

992 """Controlled Pauli-Z gate.""" 

993 

994 def __init__(self): 

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

996 

997 def to_ir(self, target: QubitSet): 

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

999 

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

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

1002 

1003 @staticmethod 

1004 @circuit.subroutine(register=True) 

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

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

1007 

1008 Args: 

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

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

1011 

1012 Returns: 

1013 Instruction: CZ instruction. 

1014 

1015 Examples: 

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

1017 """ 

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

1019 

1020 

1021Gate.register_gate(CZ) 

1022 

1023 

1024class XX(AngledGate): 

1025 """Ising XX coupling gate. 

1026 

1027 Reference: https://arxiv.org/abs/1707.06356 

1028 

1029 Args: 

1030 angle (float): angle in radians. 

1031 """ 

1032 

1033 def __init__(self, angle: float): 

1034 super().__init__( 

1035 angle=angle, 

1036 qubit_count=2, 

1037 ascii_symbols=["XX({:.3g})".format(angle), "XX({:.3g})".format(angle)], 

1038 ) 

1039 

1040 def to_ir(self, target: QubitSet): 

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

1042 

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

1044 cos = np.cos(self.angle / 2) 

1045 isin = 1.0j * np.sin(self.angle / 2) 

1046 return np.array( 

1047 [ 

1048 [cos, 0.0, 0.0, -isin], 

1049 [0.0, cos, -isin, 0.0], 

1050 [0.0, -isin, cos, 0.0], 

1051 [-isin, 0.0, 0.0, cos], 

1052 ], 

1053 dtype=complex, 

1054 ) 

1055 

1056 @staticmethod 

1057 @circuit.subroutine(register=True) 

1058 def xx(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction: 

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

1060 

1061 Args: 

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

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

1064 angle (float): Angle in radians. 

1065 

1066 Returns: 

1067 Instruction: XX instruction. 

1068 

1069 Examples: 

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

1071 """ 

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

1073 

1074 

1075Gate.register_gate(XX) 

1076 

1077 

1078class YY(AngledGate): 

1079 """Ising YY coupling gate. 

1080 

1081 Reference: https://arxiv.org/abs/1707.06356 

1082 

1083 Args: 

1084 angle (float): angle in radians. 

1085 """ 

1086 

1087 def __init__(self, angle: float): 

1088 super().__init__( 

1089 angle=angle, 

1090 qubit_count=2, 

1091 ascii_symbols=["YY({:.3g})".format(angle), "YY({:.3g})".format(angle)], 

1092 ) 

1093 

1094 def to_ir(self, target: QubitSet): 

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

1096 

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

1098 cos = np.cos(self.angle / 2) 

1099 isin = 1.0j * np.sin(self.angle / 2) 

1100 return np.array( 

1101 [ 

1102 [cos, 0.0, 0.0, isin], 

1103 [0.0, cos, -isin, 0.0], 

1104 [0.0, -isin, cos, 0.0], 

1105 [isin, 0.0, 0.0, cos], 

1106 ], 

1107 dtype=complex, 

1108 ) 

1109 

1110 @staticmethod 

1111 @circuit.subroutine(register=True) 

1112 def yy(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction: 

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

1114 

1115 Args: 

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

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

1118 angle (float): Angle in radians. 

1119 

1120 Returns: 

1121 Instruction: YY instruction. 

1122 

1123 Examples: 

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

1125 """ 

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

1127 

1128 

1129Gate.register_gate(YY) 

1130 

1131 

1132class ZZ(AngledGate): 

1133 """Ising ZZ coupling gate. 

1134 

1135 Reference: https://arxiv.org/abs/1707.06356 

1136 

1137 Args: 

1138 angle (float): angle in radians. 

1139 """ 

1140 

1141 def __init__(self, angle: float): 

1142 super().__init__( 

1143 angle=angle, 

1144 qubit_count=2, 

1145 ascii_symbols=["ZZ({:.3g})".format(angle), "ZZ({:.3g})".format(angle)], 

1146 ) 

1147 

1148 def to_ir(self, target: QubitSet): 

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

1150 

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

1152 return np.array( 

1153 [ 

1154 [np.exp(-1j * (self.angle / 2)), 0.0, 0.0, 0.0], 

1155 [0.0, np.exp(1j * (self.angle / 2)), 0.0, 0.0], 

1156 [0.0, 0.0, np.exp(1j * (self.angle / 2)), 0.0], 

1157 [0.0, 0.0, 0.0, np.exp(-1j * (self.angle / 2))], 

1158 ], 

1159 dtype=complex, 

1160 ) 

1161 

1162 @staticmethod 

1163 @circuit.subroutine(register=True) 

1164 def zz(target1: QubitInput, target2: QubitInput, angle: float) -> Instruction: 

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

1166 

1167 Args: 

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

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

1170 angle (float): Angle in radians. 

1171 

1172 Returns: 

1173 Instruction: ZZ instruction. 

1174 

1175 Examples: 

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

1177 """ 

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

1179 

1180 

1181Gate.register_gate(ZZ) 

1182 

1183 

1184# Three qubit gates # 

1185 

1186 

1187class CCNot(Gate): 

1188 """CCNOT gate or Toffoli gate.""" 

1189 

1190 def __init__(self): 

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

1192 

1193 def to_ir(self, target: QubitSet): 

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

1195 

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

1197 return np.array( 

1198 [ 

1199 [1, 0, 0, 0, 0, 0, 0, 0], 

1200 [0, 1, 0, 0, 0, 0, 0, 0], 

1201 [0, 0, 1, 0, 0, 0, 0, 0], 

1202 [0, 0, 0, 1, 0, 0, 0, 0], 

1203 [0, 0, 0, 0, 1, 0, 0, 0], 

1204 [0, 0, 0, 0, 0, 1, 0, 0], 

1205 [0, 0, 0, 0, 0, 0, 0, 1], 

1206 [0, 0, 0, 0, 0, 0, 1, 0], 

1207 ], 

1208 dtype=complex, 

1209 ) 

1210 

1211 @staticmethod 

1212 @circuit.subroutine(register=True) 

1213 def ccnot(control1: QubitInput, control2: QubitInput, target: QubitInput) -> Instruction: 

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

1215 

1216 Args: 

1217 control1 (Qubit or int): Control qubit 1 index. 

1218 control2 (Qubit or int): Control qubit 2 index. 

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

1220 

1221 Returns: 

1222 Instruction: CCNot instruction. 

1223 

1224 Examples: 

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

1226 """ 

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

1228 

1229 

1230Gate.register_gate(CCNot) 

1231 

1232 

1233class CSwap(Gate): 

1234 """Controlled Swap gate.""" 

1235 

1236 def __init__(self): 

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

1238 

1239 def to_ir(self, target: QubitSet): 

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

1241 

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

1243 return np.array( 

1244 [ 

1245 [1, 0, 0, 0, 0, 0, 0, 0], 

1246 [0, 1, 0, 0, 0, 0, 0, 0], 

1247 [0, 0, 1, 0, 0, 0, 0, 0], 

1248 [0, 0, 0, 1, 0, 0, 0, 0], 

1249 [0, 0, 0, 0, 1, 0, 0, 0], 

1250 [0, 0, 0, 0, 0, 0, 1, 0], 

1251 [0, 0, 0, 0, 0, 1, 0, 0], 

1252 [0, 0, 0, 0, 0, 0, 0, 1], 

1253 ], 

1254 dtype=complex, 

1255 ) 

1256 

1257 @staticmethod 

1258 @circuit.subroutine(register=True) 

1259 def cswap(control: QubitInput, target1: QubitInput, target2: QubitInput) -> Instruction: 

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

1261 

1262 Args: 

1263 control (Qubit or int): Control qubit index 

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

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

1266 

1267 Returns: 

1268 Instruction: CSwap instruction. 

1269 

1270 Examples: 

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

1272 """ 

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

1274 

1275 

1276Gate.register_gate(CSwap) 

1277 

1278 

1279class Unitary(Gate): 

1280 """Arbitrary unitary gate 

1281 

1282 Args: 

1283 matrix (numpy.ndarray): Unitary matrix which defines the gate. 

1284 display_name (str): Name to be used for an instance of this unitary gate 

1285 for circuit diagrams. Defaults to `U`. 

1286 

1287 Raises: 

1288 ValueError: If `matrix` is not a two-dimensional square matrix, 

1289 or has a dimension length which is not a positive exponent of 2, 

1290 or is non-unitary. 

1291 """ 

1292 

1293 def __init__(self, matrix: np.ndarray, display_name: str = "U"): 

1294 verify_quantum_operator_matrix_dimensions(matrix) 

1295 self._matrix = np.array(matrix, dtype=complex) 

1296 qubit_count = int(np.log2(self._matrix.shape[0])) 

1297 

1298 if not is_unitary(self._matrix): 

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

1300 

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

1302 

1303 def to_matrix(self): 

1304 return np.array(self._matrix) 

1305 

1306 def to_ir(self, target: QubitSet): 

1307 return ir.Unitary.construct( 

1308 targets=[qubit for qubit in target], 

1309 matrix=Unitary._transform_matrix_to_ir(self._matrix), 

1310 ) 

1311 

1312 @staticmethod 

1313 def _transform_matrix_to_ir(matrix: np.ndarray): 

1314 return [[[element.real, element.imag] for element in row] for row in matrix.tolist()] 

1315 

1316 @staticmethod 

1317 @circuit.subroutine(register=True) 

1318 def unitary(targets: QubitSet, matrix: np.ndarray, display_name: str = "U") -> Instruction: 

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

1320 

1321 Args: 

1322 targets (QubitSet): Target qubits. 

1323 matrix (numpy.ndarray): Unitary matrix which defines the gate. Matrix should be 

1324 compatible with the supplied targets, with 2 ** len(targets) == matrix.shape[0]. 

1325 display_name (str): Name to be used for an instance of this unitary gate 

1326 for circuit diagrams. Defaults to `U`. 

1327 

1328 Returns: 

1329 Instruction: Unitary instruction. 

1330 

1331 Raises: 

1332 ValueError: If `matrix` is not a two-dimensional square matrix, 

1333 or has a dimension length which is not compatible with the `targets`, 

1334 or is non-unitary, 

1335 

1336 Examples: 

1337 >>> circ = Circuit().unitary(matrix=np.array([[0, 1],[1, 0]]), targets=[0]) 

1338 """ 

1339 if 2 ** len(targets) != matrix.shape[0]: 

1340 raise ValueError("Dimensions of the supplied unitary are incompatible with the targets") 

1341 

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

1343 

1344 

1345Gate.register_gate(Unitary)