Skip to content

Commit

Permalink
first version of gphase
Browse files Browse the repository at this point in the history
  • Loading branch information
jcjaskula-aws committed Nov 15, 2023
1 parent 0c2c9e8 commit c3044cb
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 6 deletions.
11 changes: 9 additions & 2 deletions src/braket/circuits/braket_program_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,15 @@ def is_builtin_gate(self, name: str) -> bool:
user_defined_gate = self.is_user_defined_gate(name)
return name in BRAKET_GATES and not user_defined_gate

def add_phase_instruction(self, target: tuple[int], phase_value: int) -> None:
raise NotImplementedError
def add_phase_instruction(self, target: tuple[int], phase_value: float) -> None:
"""Add a global phase to the circuit.
Args:
target (tuple[int]): Unused
phase_value (float): The phase value to be applied
"""
instruction = Instruction(BRAKET_GATES["gphase"](phase_value))
self._circuit.add_instruction(instruction)

Check warning on line 67 in src/braket/circuits/braket_program_context.py

View check run for this annotation

Codecov / codecov/patch

src/braket/circuits/braket_program_context.py#L66-L67

Added lines #L66 - L67 were not covered by tests

def add_gate_instruction(
self, gate_name: str, target: tuple[int], *params, ctrl_modifiers: list[int], power: float
Expand Down
2 changes: 1 addition & 1 deletion src/braket/circuits/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def _to_openqasm(

return (
f"{inv_prefix}{power_prefix}{control_prefix}"
f"{self._qasm_name}{param_string} {', '.join(qubits)};"
f"{self._qasm_name}{param_string}{','.join([f' {qubit}' for qubit in qubits])};"
)

@property
Expand Down
76 changes: 75 additions & 1 deletion src/braket/circuits/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,80 @@ def i(
Gate.register_gate(I)


class GPhase(AngledGate):
"""Z-axis rotation gate.
Args:
angle (Union[FreeParameterExpression, float]): angle in radians.
"""

def __init__(self, angle: Union[FreeParameterExpression, float]):
# Avoid parent constructor because _qubit_count must be zero
self._qubit_count = self.fixed_qubit_count()
self._ascii_symbols = []

if angle is None:
raise ValueError("angle must not be None")

Check warning on line 205 in src/braket/circuits/gates.py

View check run for this annotation

Codecov / codecov/patch

src/braket/circuits/gates.py#L205

Added line #L205 was not covered by tests
if isinstance(angle, FreeParameterExpression):
self._parameters = [angle]
else:
self._parameters = [float(angle)] # explicit casting in case angle is e.g. np.float32

@property
def _qasm_name(self) -> str:
return "gphase"

Check warning on line 213 in src/braket/circuits/gates.py

View check run for this annotation

Codecov / codecov/patch

src/braket/circuits/gates.py#L213

Added line #L213 was not covered by tests

def adjoint(self) -> list[Gate]:
return [GPhase(-self.angle)]

def to_matrix(self) -> np.ndarray:
return np.exp(1j * self.angle) * np.eye(1)

def bind_values(self, **kwargs) -> AngledGate:
return get_angle(self, **kwargs)

@staticmethod
def fixed_qubit_count() -> int:
return 0

@staticmethod
@circuit.subroutine(register=True)
def gphase(
angle: Union[FreeParameterExpression, float],
*,
control: Optional[QubitSetInput] = None,
control_state: Optional[BasisStateInput] = None,
power: float = 1,
) -> Instruction:
"""Registers this function into the circuit class.
Args:
angle (Union[FreeParameterExpression, float]): Phase in radians.
control (Optional[QubitSetInput]): Control qubit(s). Default None.
control_state (Optional[BasisStateInput]): Quantum state on which to control the
operation. Must be a binary sequence of same length as number of qubits in
`control`. Will be ignored if `control` is not present. May be represented as a
string, list, or int. For example "0101", [0, 1, 0, 1], 5 all represent
controlling on qubits 0 and 2 being in the \\|0⟩ state and qubits 1 and 3 being
in the \\|1⟩ state. Default "1" * len(control).
power (float): Integer or fractional power to raise the gate to. Negative
powers will be split into an inverse, accompanied by the positive power.
Default 1.
Returns:
Instruction: GPhase instruction d.
Examples:
>>> circ = Circuit().gphase(0.45)
"""
return [
Instruction(GPhase(angle), control=control, control_state=control_state, power=power)
]


Gate.register_gate(GPhase)


class X(Gate):
"""Pauli-X gate."""

Expand Down Expand Up @@ -1155,7 +1229,7 @@ def adjoint(self) -> list[Gate]:
def fixed_qubit_count() -> int:
return 1

def bind_values(self, **kwargs) -> U:
def bind_values(self, **kwargs) -> TripleAngledGate:
return _get_angles(self, **kwargs)

@staticmethod
Expand Down
1 change: 1 addition & 0 deletions src/braket/circuits/translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from braket.ir.jaqcd.program_v1 import Results

BRAKET_GATES = {
"gphase": braket_gates.GPhase,
"i": braket_gates.I,
"h": braket_gates.H,
"x": braket_gates.X,
Expand Down
17 changes: 15 additions & 2 deletions test/unit_tests/braket/circuits/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@
from braket.pulse import ArbitraryWaveform, Frame, Port, PulseSequence


class NoTarget:
pass


class TripleAngle:
pass


testdata = [
(Gate.H, "h", ir.H, [SingleTarget], {}),
(Gate.GPhase, "gphase", None, [NoTarget, Angle], {}),
(Gate.I, "i", ir.I, [SingleTarget], {}),
(Gate.X, "x", ir.X, [SingleTarget], {}),
(Gate.Y, "y", ir.Y, [SingleTarget], {}),
Expand Down Expand Up @@ -119,6 +124,7 @@ class TripleAngle:
]

parameterizable_gates = [
Gate.GPhase,
Gate.Rx,
Gate.Ry,
Gate.Rz,
Expand Down Expand Up @@ -149,6 +155,10 @@ class TripleAngle:
]


def no_target_valid_input(**kwargs):
return {}


def single_target_valid_input(**kwargs):
return {"target": 2}

Expand Down Expand Up @@ -195,6 +205,7 @@ def two_dimensional_matrix_valid_input(**kwargs):


valid_ir_switcher = {
"NoTarget": no_target_valid_input,
"SingleTarget": single_target_valid_input,
"DoubleTarget": double_target_valid_ir_input,
"Angle": angle_valid_input,
Expand Down Expand Up @@ -236,7 +247,9 @@ def create_valid_target_input(irsubclasses):
qubit_set = []
# based on the concept that control goes first in target input
for subclass in irsubclasses:
if subclass == SingleTarget:
if subclass == NoTarget:
qubit_set.extend(list(no_target_valid_input().values()))
elif subclass == SingleTarget:
qubit_set.extend(list(single_target_valid_input().values()))
elif subclass == DoubleTarget:
qubit_set.extend(list(double_target_valid_ir_input().values()))
Expand Down Expand Up @@ -284,7 +297,7 @@ def calculate_qubit_count(irsubclasses):
qubit_count += 2
elif subclass == MultiTarget:
qubit_count += 3
elif subclass in (Angle, TwoDimensionalMatrix, TripleAngle):
elif subclass in (NoTarget, Angle, TwoDimensionalMatrix, TripleAngle):
pass
else:
raise ValueError("Invalid subclass")
Expand Down

0 comments on commit c3044cb

Please sign in to comment.