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.qubit import QubitInput 

24from braket.circuits.qubit_set import QubitSet, QubitSetInput 

25 

26# TODO: look into adding angle to diagrams 

27 

28""" 

29To add a new gate: 

30 1. Implement the class and extend `Gate` 

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

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

33 clients add this gate to a circuit. 

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

35""" 

36 

37# Single qubit gates # 

38 

39 

40class H(Gate): 

41 """Hadamard gate.""" 

42 

43 def __init__(self): 

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

45 

46 def to_ir(self, target: QubitSet): 

47 return ir.H(target=target[0]) 

48 

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

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

51 

52 @staticmethod 

53 @circuit.subroutine(register=True) 

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

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

56 

57 Args: 

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

59 

60 Returns: 

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

62 

63 Examples: 

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

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

66 """ 

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

68 

69 

70Gate.register_gate(H) 

71 

72 

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

74 """Identity gate.""" 

75 

76 def __init__(self): 

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

78 

79 def to_ir(self, target: QubitSet): 

80 return ir.I(target=target[0]) 

81 

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

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

84 

85 @staticmethod 

86 @circuit.subroutine(register=True) 

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

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

89 

90 Args: 

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

92 

93 Returns: 

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

95 

96 Examples: 

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

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

99 """ 

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

101 

102 

103Gate.register_gate(I) 

104 

105 

106class X(Gate): 

107 """Pauli-X gate.""" 

108 

109 def __init__(self): 

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

111 

112 def to_ir(self, target: QubitSet): 

113 return ir.X(target=target[0]) 

114 

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

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

117 

118 @staticmethod 

119 @circuit.subroutine(register=True) 

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

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

122 

123 Args: 

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

125 

126 Returns: 

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

128 

129 Examples: 

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

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

132 """ 

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

134 

135 

136Gate.register_gate(X) 

137 

138 

139class Y(Gate): 

140 """Pauli-Y gate.""" 

141 

142 def __init__(self): 

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

144 

145 def to_ir(self, target: QubitSet): 

146 return ir.Y(target=target[0]) 

147 

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

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

150 

151 @staticmethod 

152 @circuit.subroutine(register=True) 

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

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

155 

156 Args: 

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

158 

159 Returns: 

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

161 

162 Examples: 

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

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

165 """ 

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

167 

168 

169Gate.register_gate(Y) 

170 

171 

172class Z(Gate): 

173 """Pauli-Z gate.""" 

174 

175 def __init__(self): 

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

177 

178 def to_ir(self, target: QubitSet): 

179 return ir.Z(target=target[0]) 

180 

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

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

183 

184 @staticmethod 

185 @circuit.subroutine(register=True) 

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

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

188 

189 Args: 

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

191 

192 Returns: 

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

194 

195 Examples: 

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

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

198 """ 

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

200 

201 

202Gate.register_gate(Z) 

203 

204 

205class S(Gate): 

206 """S gate.""" 

207 

208 def __init__(self): 

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

210 

211 def to_ir(self, target: QubitSet): 

212 return ir.S(target=target[0]) 

213 

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

215 

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

217 

218 @staticmethod 

219 @circuit.subroutine(register=True) 

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

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

222 

223 Args: 

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

225 

226 Returns: 

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

228 

229 Examples: 

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

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

232 """ 

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

234 

235 

236Gate.register_gate(S) 

237 

238 

239class Si(Gate): 

240 """Conjugate transpose of S gate.""" 

241 

242 def __init__(self): 

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

244 

245 def to_ir(self, target: QubitSet): 

246 return ir.Si(target=target[0]) 

247 

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

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

250 

251 @staticmethod 

252 @circuit.subroutine(register=True) 

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

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

255 

256 Args: 

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

258 

259 Returns: 

260 Iterable[Instruction]: Iterable of Si instructions. 

261 

262 Examples: 

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

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

265 """ 

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

267 

268 

269Gate.register_gate(Si) 

270 

271 

272class T(Gate): 

273 """T gate.""" 

274 

275 def __init__(self): 

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

277 

278 def to_ir(self, target: QubitSet): 

279 return ir.T(target=target[0]) 

280 

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

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

283 

284 @staticmethod 

285 @circuit.subroutine(register=True) 

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

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

288 

289 Args: 

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

291 

292 Returns: 

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

294 

295 Examples: 

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

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

298 """ 

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

300 

301 

302Gate.register_gate(T) 

303 

304 

305class Ti(Gate): 

306 """Conjugate transpose of T gate.""" 

307 

308 def __init__(self): 

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

310 

311 def to_ir(self, target: QubitSet): 

312 return ir.Ti(target=target[0]) 

313 

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

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

316 

317 @staticmethod 

318 @circuit.subroutine(register=True) 

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

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

321 

322 Args: 

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

324 

325 Returns: 

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

327 

328 Examples: 

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

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

331 """ 

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

333 

334 

335Gate.register_gate(Ti) 

336 

337 

338class V(Gate): 

339 """Square root of not gate.""" 

340 

341 def __init__(self): 

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

343 

344 def to_ir(self, target: QubitSet): 

345 return ir.V(target=target[0]) 

346 

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

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

349 

350 @staticmethod 

351 @circuit.subroutine(register=True) 

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

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

354 

355 Args: 

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

357 

358 Returns: 

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

360 

361 Examples: 

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

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

364 """ 

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

366 

367 

368Gate.register_gate(V) 

369 

370 

371class Vi(Gate): 

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

373 

374 def __init__(self): 

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

376 

377 def to_ir(self, target: QubitSet): 

378 return ir.Vi(target=target[0]) 

379 

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

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

382 

383 @staticmethod 

384 @circuit.subroutine(register=True) 

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

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

387 

388 Args: 

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

390 

391 Returns: 

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

393 

394 Examples: 

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

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

397 """ 

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

399 

400 

401Gate.register_gate(Vi) 

402 

403 

404# Single qubit gates with rotation # 

405 

406 

407class Rx(AngledGate): 

408 """X-axis rotation gate. 

409 

410 Args: 

411 angle (float): angle in radians. 

412 """ 

413 

414 def __init__(self, angle: float): 

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

416 

417 def to_ir(self, target: QubitSet): 

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

419 

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

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

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

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

424 

425 @staticmethod 

426 @circuit.subroutine(register=True) 

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

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

429 

430 Args: 

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

432 angle (float): Angle in radians. 

433 

434 Returns: 

435 Instruction: Rx instruction. 

436 

437 Examples: 

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

439 """ 

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

441 

442 

443Gate.register_gate(Rx) 

444 

445 

446class Ry(AngledGate): 

447 """Y-axis rotation gate. 

448 

449 Args: 

450 angle (float): angle in radians. 

451 """ 

452 

453 def __init__(self, angle: float): 

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

455 

456 def to_ir(self, target: QubitSet): 

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

458 

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

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

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

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

463 

464 @staticmethod 

465 @circuit.subroutine(register=True) 

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

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

468 

469 Args: 

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

471 angle (float): Angle in radians. 

472 

473 Returns: 

474 Instruction: Ry instruction. 

475 

476 Examples: 

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

478 """ 

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

480 

481 

482Gate.register_gate(Ry) 

483 

484 

485class Rz(AngledGate): 

486 """Z-axis rotation gate. 

487 

488 Args: 

489 angle (float): angle in radians. 

490 """ 

491 

492 def __init__(self, angle: float): 

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

494 

495 def to_ir(self, target: QubitSet): 

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

497 

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

499 return np.array( 

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

501 ) 

502 

503 @staticmethod 

504 @circuit.subroutine(register=True) 

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

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

507 

508 Args: 

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

510 angle (float): Angle in radians. 

511 

512 Returns: 

513 Instruction: Rz instruction. 

514 

515 Examples: 

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

517 """ 

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

519 

520 

521Gate.register_gate(Rz) 

522 

523 

524class PhaseShift(AngledGate): 

525 """Phase shift gate. 

526 

527 Args: 

528 angle (float): angle in radians. 

529 """ 

530 

531 def __init__(self, angle: float): 

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

533 

534 def to_ir(self, target: QubitSet): 

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

536 

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

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

539 

540 @staticmethod 

541 @circuit.subroutine(register=True) 

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

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

544 

545 Args: 

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

547 angle (float): Angle in radians. 

548 

549 Returns: 

550 Instruction: PhaseShift instruction. 

551 

552 Examples: 

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

554 """ 

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

556 

557 

558Gate.register_gate(PhaseShift) 

559 

560 

561# Two qubit gates # 

562 

563 

564class CNot(Gate): 

565 """Controlled NOT gate.""" 

566 

567 def __init__(self): 

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

569 

570 def to_ir(self, target: QubitSet): 

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

572 

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

574 return np.array( 

575 [ 

576 [1.0, 0.0, 0.0, 0.0], 

577 [0.0, 1.0, 0.0, 0.0], 

578 [0.0, 0.0, 0.0, 1.0], 

579 [0.0, 0.0, 1.0, 0.0], 

580 ], 

581 dtype=complex, 

582 ) 

583 

584 @staticmethod 

585 @circuit.subroutine(register=True) 

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

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

588 

589 Args: 

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

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

592 

593 Returns: 

594 Instruction: CNot instruction. 

595 

596 Examples: 

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

598 """ 

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

600 

601 

602Gate.register_gate(CNot) 

603 

604 

605class Swap(Gate): 

606 """Swap gate.""" 

607 

608 def __init__(self): 

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

610 

611 def to_ir(self, target: QubitSet): 

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

613 

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

615 return np.array( 

616 [ 

617 [1.0, 0.0, 0.0, 0.0], 

618 [0.0, 0.0, 1.0, 0.0], 

619 [0.0, 1.0, 0.0, 0.0], 

620 [0.0, 0.0, 0.0, 1.0], 

621 ], 

622 dtype=complex, 

623 ) 

624 

625 @staticmethod 

626 @circuit.subroutine(register=True) 

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

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

629 

630 Args: 

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

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

633 

634 Returns: 

635 Instruction: Swap instruction. 

636 

637 Examples: 

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

639 """ 

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

641 

642 

643Gate.register_gate(Swap) 

644 

645 

646class ISwap(Gate): 

647 """ISwap gate.""" 

648 

649 def __init__(self): 

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

651 

652 def to_ir(self, target: QubitSet): 

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

654 

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

656 return np.array( 

657 [ 

658 [1.0, 0.0, 0.0, 0.0], 

659 [0.0, 0.0, 1.0j, 0.0], 

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

661 [0.0, 0.0, 0.0, 1.0], 

662 ], 

663 dtype=complex, 

664 ) 

665 

666 @staticmethod 

667 @circuit.subroutine(register=True) 

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

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

670 

671 Args: 

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

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

674 

675 Returns: 

676 Instruction: ISwap instruction. 

677 

678 Examples: 

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

680 """ 

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

682 

683 

684Gate.register_gate(ISwap) 

685 

686 

687class PSwap(AngledGate): 

688 """PSwap gate. 

689 

690 Args: 

691 angle (float): angle in radians. 

692 """ 

693 

694 def __init__(self, angle: float): 

695 super().__init__( 

696 angle=angle, 

697 qubit_count=2, 

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

699 ) 

700 

701 def to_ir(self, target: QubitSet): 

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

703 

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

705 return np.array( 

706 [ 

707 [1.0, 0.0, 0.0, 0.0], 

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

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

710 [0.0, 0.0, 0.0, 1.0], 

711 ], 

712 dtype=complex, 

713 ) 

714 

715 @staticmethod 

716 @circuit.subroutine(register=True) 

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

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

719 

720 Args: 

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

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

723 

724 Returns: 

725 Instruction: PSwap instruction. 

726 

727 Examples: 

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

729 """ 

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

731 

732 

733Gate.register_gate(PSwap) 

734 

735 

736class XY(AngledGate): 

737 """XY gate. 

738 

739 Args: 

740 angle (float): angle in radians. 

741 """ 

742 

743 def __init__(self, angle: float): 

744 super().__init__( 

745 angle=angle, 

746 qubit_count=2, 

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

748 ) 

749 

750 def to_ir(self, target: QubitSet): 

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

752 

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

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

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

756 return np.array( 

757 [ 

758 [1.0, 0.0, 0.0, 0.0], 

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

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

761 [0.0, 0.0, 0.0, 1.0], 

762 ], 

763 dtype=complex, 

764 ) 

765 

766 @staticmethod 

767 @circuit.subroutine(register=True) 

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

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

770 

771 Args: 

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

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

774 

775 Returns: 

776 Instruction: XY instruction. 

777 

778 Examples: 

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

780 """ 

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

782 

783 

784Gate.register_gate(XY) 

785 

786 

787class CPhaseShift(AngledGate): 

788 """Controlled phase shift gate. 

789 

790 Args: 

791 angle (float): angle in radians. 

792 """ 

793 

794 def __init__(self, angle: float): 

795 super().__init__( 

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

797 ) 

798 

799 def to_ir(self, target: QubitSet): 

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

801 

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

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

804 

805 @staticmethod 

806 @circuit.subroutine(register=True) 

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

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

809 

810 Args: 

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

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

813 angle (float): Angle in radians. 

814 

815 Returns: 

816 Instruction: CPhaseShift instruction. 

817 

818 Examples: 

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

820 """ 

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

822 

823 

824Gate.register_gate(CPhaseShift) 

825 

826 

827class CPhaseShift00(AngledGate): 

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

829 

830 Args: 

831 angle (float): angle in radians. 

832 """ 

833 

834 def __init__(self, angle: float): 

835 super().__init__( 

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

837 ) 

838 

839 def to_ir(self, target: QubitSet): 

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

841 

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

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

844 

845 @staticmethod 

846 @circuit.subroutine(register=True) 

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

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

849 

850 Args: 

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

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

853 angle (float): Angle in radians. 

854 

855 Returns: 

856 Instruction: CPhaseShift00 instruction. 

857 

858 Examples: 

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

860 """ 

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

862 

863 

864Gate.register_gate(CPhaseShift00) 

865 

866 

867class CPhaseShift01(AngledGate): 

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

869 

870 Args: 

871 angle (float): angle in radians. 

872 """ 

873 

874 def __init__(self, angle: float): 

875 super().__init__( 

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

877 ) 

878 

879 def to_ir(self, target: QubitSet): 

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

881 

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

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

884 

885 @staticmethod 

886 @circuit.subroutine(register=True) 

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

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

889 

890 Args: 

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

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

893 angle (float): Angle in radians. 

894 

895 Returns: 

896 Instruction: CPhaseShift01 instruction. 

897 

898 Examples: 

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

900 """ 

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

902 

903 

904Gate.register_gate(CPhaseShift01) 

905 

906 

907class CPhaseShift10(AngledGate): 

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

909 

910 Args: 

911 angle (float): angle in radians. 

912 """ 

913 

914 def __init__(self, angle: float): 

915 super().__init__( 

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

917 ) 

918 

919 def to_ir(self, target: QubitSet): 

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

921 

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

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

924 

925 @staticmethod 

926 @circuit.subroutine(register=True) 

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

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

929 

930 Args: 

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

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

933 angle (float): Angle in radians. 

934 

935 Returns: 

936 Instruction: CPhaseShift10 instruction. 

937 

938 Examples: 

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

940 """ 

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

942 

943 

944Gate.register_gate(CPhaseShift10) 

945 

946 

947class CY(Gate): 

948 """Controlled Pauli-Y gate.""" 

949 

950 def __init__(self): 

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

952 

953 def to_ir(self, target: QubitSet): 

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

955 

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

957 return np.array( 

958 [ 

959 [1.0, 0.0, 0.0, 0.0], 

960 [0.0, 1.0, 0.0, 0.0], 

961 [0.0, 0.0, 0.0, -1.0j], 

962 [0.0, 0.0, +1.0j, 0.0], 

963 ], 

964 dtype=complex, 

965 ) 

966 

967 @staticmethod 

968 @circuit.subroutine(register=True) 

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

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

971 

972 Args: 

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

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

975 

976 Returns: 

977 Instruction: CY instruction. 

978 

979 Examples: 

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

981 """ 

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

983 

984 

985Gate.register_gate(CY) 

986 

987 

988class CZ(Gate): 

989 """Controlled Pauli-Z gate.""" 

990 

991 def __init__(self): 

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

993 

994 def to_ir(self, target: QubitSet): 

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

996 

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

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

999 

1000 @staticmethod 

1001 @circuit.subroutine(register=True) 

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

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

1004 

1005 Args: 

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

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

1008 

1009 Returns: 

1010 Instruction: CZ instruction. 

1011 

1012 Examples: 

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

1014 """ 

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

1016 

1017 

1018Gate.register_gate(CZ) 

1019 

1020 

1021class XX(AngledGate): 

1022 """Ising XX coupling gate. 

1023 

1024 Args: 

1025 angle (float): angle in radians. 

1026 """ 

1027 

1028 def __init__(self, angle: float): 

1029 super().__init__( 

1030 angle=angle, 

1031 qubit_count=2, 

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

1033 ) 

1034 

1035 def to_ir(self, target: QubitSet): 

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

1037 

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

1039 return (1 / math.sqrt(2)) * np.array( 

1040 [ 

1041 [1.0, 0.0, 0.0, -1.0j * np.exp(1.0j * self.angle)], 

1042 [0.0, 1.0, -1.0j, 0.0], 

1043 [0.0, -1.0j, 1.0, 0.0], 

1044 [-1.0j * np.exp(-1.0j * self.angle), 0.0, 0.0, 1.0], 

1045 ], 

1046 dtype=complex, 

1047 ) 

1048 

1049 @staticmethod 

1050 @circuit.subroutine(register=True) 

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

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

1053 

1054 Args: 

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

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

1057 angle (float): Angle in radians. 

1058 

1059 Returns: 

1060 Instruction: XX instruction. 

1061 

1062 Examples: 

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

1064 """ 

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

1066 

1067 

1068Gate.register_gate(XX) 

1069 

1070 

1071class YY(AngledGate): 

1072 """Ising YY coupling gate. 

1073 

1074 Args: 

1075 angle (float): angle in radians. 

1076 """ 

1077 

1078 def __init__(self, angle: float): 

1079 super().__init__( 

1080 angle=angle, 

1081 qubit_count=2, 

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

1083 ) 

1084 

1085 def to_ir(self, target: QubitSet): 

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

1087 

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

1089 cos = np.cos(self.angle) 

1090 sin = np.sin(self.angle) 

1091 return np.array( 

1092 [ 

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

1094 [0.0, cos, -1.0j * sin, 0.0], 

1095 [0.0, -1.0j * sin, cos, 0.0], 

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

1097 ], 

1098 dtype=complex, 

1099 ) 

1100 

1101 @staticmethod 

1102 @circuit.subroutine(register=True) 

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

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

1105 

1106 Args: 

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

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

1109 angle (float): Angle in radians. 

1110 

1111 Returns: 

1112 Instruction: YY instruction. 

1113 

1114 Examples: 

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

1116 """ 

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

1118 

1119 

1120Gate.register_gate(YY) 

1121 

1122 

1123class ZZ(AngledGate): 

1124 """Ising ZZ coupling gate. 

1125 

1126 Args: 

1127 angle (float): angle in radians. 

1128 """ 

1129 

1130 def __init__(self, angle: float): 

1131 super().__init__( 

1132 angle=angle, 

1133 qubit_count=2, 

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

1135 ) 

1136 

1137 def to_ir(self, target: QubitSet): 

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

1139 

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

1141 return np.array( 

1142 [ 

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

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

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

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

1147 ], 

1148 dtype=complex, 

1149 ) 

1150 

1151 @staticmethod 

1152 @circuit.subroutine(register=True) 

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

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

1155 

1156 Args: 

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

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

1159 angle (float): Angle in radians. 

1160 

1161 Returns: 

1162 Instruction: ZZ instruction. 

1163 

1164 Examples: 

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

1166 """ 

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

1168 

1169 

1170Gate.register_gate(ZZ) 

1171 

1172 

1173# Three qubit gates # 

1174 

1175 

1176class CCNot(Gate): 

1177 """CCNOT gate or Toffoli gate.""" 

1178 

1179 def __init__(self): 

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

1181 

1182 def to_ir(self, target: QubitSet): 

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

1184 

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

1186 return np.array( 

1187 [ 

1188 [1, 0, 0, 0, 0, 0, 0, 0], 

1189 [0, 1, 0, 0, 0, 0, 0, 0], 

1190 [0, 0, 1, 0, 0, 0, 0, 0], 

1191 [0, 0, 0, 1, 0, 0, 0, 0], 

1192 [0, 0, 0, 0, 1, 0, 0, 0], 

1193 [0, 0, 0, 0, 0, 1, 0, 0], 

1194 [0, 0, 0, 0, 0, 0, 0, 1], 

1195 [0, 0, 0, 0, 0, 0, 1, 0], 

1196 ], 

1197 dtype=complex, 

1198 ) 

1199 

1200 @staticmethod 

1201 @circuit.subroutine(register=True) 

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

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

1204 

1205 Args: 

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

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

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

1209 

1210 Returns: 

1211 Instruction: CCNot instruction. 

1212 

1213 Examples: 

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

1215 """ 

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

1217 

1218 

1219Gate.register_gate(CCNot) 

1220 

1221 

1222class CSwap(Gate): 

1223 """Controlled Swap gate.""" 

1224 

1225 def __init__(self): 

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

1227 

1228 def to_ir(self, target: QubitSet): 

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

1230 

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

1232 return np.array( 

1233 [ 

1234 [1, 0, 0, 0, 0, 0, 0, 0], 

1235 [0, 1, 0, 0, 0, 0, 0, 0], 

1236 [0, 0, 1, 0, 0, 0, 0, 0], 

1237 [0, 0, 0, 1, 0, 0, 0, 0], 

1238 [0, 0, 0, 0, 1, 0, 0, 0], 

1239 [0, 0, 0, 0, 0, 0, 1, 0], 

1240 [0, 0, 0, 0, 0, 1, 0, 0], 

1241 [0, 0, 0, 0, 0, 0, 0, 1], 

1242 ], 

1243 dtype=complex, 

1244 ) 

1245 

1246 @staticmethod 

1247 @circuit.subroutine(register=True) 

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

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

1250 

1251 Args: 

1252 control (Qubit or int): Control qubit index 

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

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

1255 

1256 Returns: 

1257 Instruction: CSwap instruction. 

1258 

1259 Examples: 

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

1261 """ 

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

1263 

1264 

1265Gate.register_gate(CSwap) 

1266 

1267 

1268class Unitary(Gate): 

1269 """Arbitrary unitary gate 

1270 

1271 Args: 

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

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

1274 for circuit diagrams. Defaults to `U`. 

1275 

1276 Raises: 

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

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

1279 or is non-unitary. 

1280 """ 

1281 

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

1283 if len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]: 

1284 raise ValueError(f"{matrix} is not a two-dimensional square matrix") 

1285 

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

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

1288 if 2 ** qubit_count != self._matrix.shape[0] or qubit_count < 1: 

1289 raise ValueError( 

1290 f"`matrix` dimension {self._matrix.shape[0]} is not a positive exponent of 2" 

1291 ) 

1292 

1293 if not Unitary._is_unitary(self._matrix): 

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

1295 

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

1297 

1298 def to_matrix(self): 

1299 return np.array(self._matrix) 

1300 

1301 def to_ir(self, target: QubitSet): 

1302 return ir.Unitary( 

1303 targets=[qubit for qubit in target], 

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

1305 ) 

1306 

1307 @staticmethod 

1308 def _is_unitary(matrix: np.ndarray): 

1309 return np.allclose(np.eye(len(matrix)), matrix.dot(matrix.T.conj())) 

1310 

1311 @staticmethod 

1312 def _transform_matrix_to_ir(matrix: np.ndarray): 

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

1314 

1315 @staticmethod 

1316 @circuit.subroutine(register=True) 

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

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

1319 

1320 Args: 

1321 targets (QubitSet): Target qubits. 

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

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

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

1325 for circuit diagrams. Defaults to `U`. 

1326 

1327 Returns: 

1328 Instruction: Unitary instruction. 

1329 

1330 Raises: 

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

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

1333 or is non-unitary, 

1334 

1335 Examples: 

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

1337 """ 

1338 if 2 ** len(targets) != matrix.shape[0]: 1338 ↛ 1339line 1338 didn't jump to line 1339, because the condition on line 1338 was never true

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

1340 

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

1342 

1343 

1344Gate.register_gate(Unitary)