|
13 | 13 |
|
14 | 14 | from __future__ import annotations
|
15 | 15 |
|
| 16 | +import inspect |
| 17 | +import sys |
16 | 18 | from abc import abstractmethod
|
17 | 19 | from numbers import Integral
|
18 | 20 | from typing import TYPE_CHECKING, Optional
|
@@ -406,6 +408,8 @@ def to_other_language(
|
406 | 408 | if self.label:
|
407 | 409 | return self.qiskit_gate(label=self.label)
|
408 | 410 | return self.qiskit_gate()
|
| 411 | + elif language == Language.BRAKET: |
| 412 | + return self.braket_gate() |
409 | 413 | elif language == Language.QASM2:
|
410 | 414 |
|
411 | 415 | instruction_str = self.qasm2_gate
|
@@ -594,6 +598,63 @@ def to_canonical_matrix(self) -> Matrix:
|
594 | 598 | )
|
595 | 599 |
|
596 | 600 |
|
| 601 | +class CP(RotationGate, ControlledGate): |
| 602 | + """Two-qubit Controlled-P gate. |
| 603 | +
|
| 604 | + Args: |
| 605 | + theta: Parameter representing the phase to apply. |
| 606 | + control: Index referring to the qubit used to control the gate. |
| 607 | + target: Index referring to the qubit on which the gate will be applied. |
| 608 | +
|
| 609 | + Example: |
| 610 | + >>> pprint(CP(0.5, 0, 1).to_matrix()) |
| 611 | + [[1, 0, 0, 0 ], |
| 612 | + [0, 1, 0, 0 ], |
| 613 | + [0, 0, 1, 0 ], |
| 614 | + [0, 0, 0, 0.87758+0.47943j]] |
| 615 | +
|
| 616 | + """ |
| 617 | + |
| 618 | + @classproperty |
| 619 | + def braket_gate(cls): |
| 620 | + from braket.circuits import gates |
| 621 | + |
| 622 | + return gates.CPhaseShift |
| 623 | + |
| 624 | + @classproperty |
| 625 | + def qiskit_gate(cls): |
| 626 | + from qiskit.circuit.library import CPhaseGate |
| 627 | + |
| 628 | + return CPhaseGate |
| 629 | + |
| 630 | + # TODO: this is a special case, see if it needs to be generalized |
| 631 | + qlm_aqasm_keyword = "CNOT;PH" |
| 632 | + qiskit_string = "cp" |
| 633 | + |
| 634 | + def __init__(self, theta: Expr | float, control: int, target: int): |
| 635 | + self.parameters = [theta] |
| 636 | + ControlledGate.__init__(self, [control], [target], P(theta, target), "CP") |
| 637 | + definition = UnitaryMatrix( |
| 638 | + self.to_canonical_matrix(), **self.native_gate_options |
| 639 | + ) |
| 640 | + ParametrizedGate.__init__(self, definition, [target], [theta], "CP") |
| 641 | + |
| 642 | + def to_canonical_matrix(self): |
| 643 | + e = exp(self.theta * 1j) # pyright: ignore[reportOperatorIssue] |
| 644 | + return np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, e]]) |
| 645 | + |
| 646 | + def __repr__(self) -> str: |
| 647 | + theta = int(self.theta) if self.theta == int(self.theta) else self.theta |
| 648 | + return f"{type(self).__name__}({theta}, {self.controls[0]}, {self.targets[0]})" |
| 649 | + |
| 650 | + def inverse(self) -> Gate: |
| 651 | + return self.__class__(-self.parameters[0], self.controls[0], self.targets[0]) |
| 652 | + |
| 653 | + nb_qubits = ( # pyright: ignore[reportAssignmentType,reportIncompatibleMethodOverride] |
| 654 | + 2 |
| 655 | + ) |
| 656 | + |
| 657 | + |
597 | 658 | class S(OneQubitNoParamGate):
|
598 | 659 | """One qubit S gate. It's equivalent to ``P(pi/2)``.
|
599 | 660 | It can also be defined as the square-root of the Z (Pauli) gate.
|
@@ -1141,7 +1202,7 @@ def to_other_language(
|
1141 | 1202 |
|
1142 | 1203 | instruction_str = self.qasm2_gate
|
1143 | 1204 | instruction_str += (
|
1144 |
| - f"({float_to_qasm_str(2 * np.pi / (2 ** float(self.k)))})" |
| 1205 | + f"({float_to_qasm_str(-2 * np.pi / (2 ** float(self.k)))})" |
1145 | 1206 | )
|
1146 | 1207 |
|
1147 | 1208 | qubits = ",".join([f"q[{j}]" for j in self.targets])
|
@@ -1402,6 +1463,26 @@ def __repr__(self) -> str:
|
1402 | 1463 | def inverse(self) -> Gate:
|
1403 | 1464 | return CRk(self.k, self.controls[0], self.targets[0])
|
1404 | 1465 |
|
| 1466 | + def to_other_language( |
| 1467 | + self, |
| 1468 | + language: Language = Language.QISKIT, |
| 1469 | + qiskit_parameters: Optional[set["Parameter"]] = None, |
| 1470 | + ): |
| 1471 | + if language == Language.QASM2: |
| 1472 | + from mpqp.qasm.mpqp_to_qasm import float_to_qasm_str |
| 1473 | + |
| 1474 | + instruction_str = self.qasm2_gate |
| 1475 | + instruction_str += ( |
| 1476 | + f"({float_to_qasm_str(-2 * np.pi / (2 ** float(self.k)))})" |
| 1477 | + ) |
| 1478 | + |
| 1479 | + qubits = ",".join([f"q[{j}]" for j in self.controls]) + "," |
| 1480 | + qubits += ",".join([f"q[{j}]" for j in self.targets]) |
| 1481 | + |
| 1482 | + return instruction_str + " " + qubits + ";" |
| 1483 | + else: |
| 1484 | + return super().to_other_language(language, qiskit_parameters) |
| 1485 | + |
1405 | 1486 |
|
1406 | 1487 | class TOF(InvolutionGate, ControlledGate, NoParameterGate):
|
1407 | 1488 | """Three-qubit Controlled-Controlled-NOT gate, also known as Toffoli Gate
|
@@ -1453,6 +1534,10 @@ def to_canonical_matrix(self):
|
1453 | 1534 | )
|
1454 | 1535 |
|
1455 | 1536 |
|
1456 |
| -NATIVE_GATES = [CNOT, CRk, CZ, H, Id, P, Rk, Rx, Ry, Rz, S, SWAP, T, TOF, U, X, Y, Z] |
1457 |
| -# 3M-TODO : check the possibility to detect when a custom gate can be defined as a native gate, problem with |
1458 |
| -# parametrized gates maybe |
| 1537 | +NATIVE_GATES = [ |
| 1538 | + cls |
| 1539 | + for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass) |
| 1540 | + if issubclass(cls, NativeGate) |
| 1541 | + and not any("ABC" in base.__name__ for base in cls.__bases__) |
| 1542 | +] |
| 1543 | +"""All concrete native gates.""" |
0 commit comments