Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add U and GPhase gates #799

Merged
merged 55 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d784d88
Add U gate
jcjaskula-aws Nov 14, 2023
9633a2a
modification according to feedback
jcjaskula-aws Nov 14, 2023
e68e78c
fix linters
jcjaskula-aws Nov 14, 2023
0c2c9e8
clean commented code
jcjaskula-aws Nov 14, 2023
c3044cb
first version of gphase
jcjaskula-aws Nov 15, 2023
d6d6886
handle drawing and control global phase
jcjaskula-aws Nov 15, 2023
388367c
Adding a global phase attribute
jcjaskula-aws Nov 17, 2023
7a52eb8
add global phase to circuit unitary
jcjaskula-aws Nov 18, 2023
d8917f3
Merge branch 'main' into jcjaskula-aws/add_u_gate
jcjaskula-aws Nov 19, 2023
f35cc38
first draft tests to check coverage
jcjaskula-aws Nov 20, 2023
fa4cb3a
add more tests
jcjaskula-aws Nov 20, 2023
5ddf96e
add test with parametric global phase
jcjaskula-aws Nov 20, 2023
3c0d766
add test for neg control qubit printing
jcjaskula-aws Nov 20, 2023
9f8a547
clean up
jcjaskula-aws Nov 20, 2023
76989f7
simplify ctrl-gphase transform
jcjaskula-aws Nov 20, 2023
f1204d0
feat: add str, repr and getitem to BasisState
ajberdy Nov 21, 2023
f5d0511
add repr coverage
ajberdy Nov 21, 2023
f68b084
add index
jcjaskula-aws Nov 21, 2023
5c56724
add pop
jcjaskula-aws Nov 21, 2023
70844ee
Merge branch 'basis-state-slice' into jcjaskula-aws/add_u_gate
jcjaskula-aws Nov 21, 2023
dabb790
fix phase target qubit
jcjaskula-aws Nov 21, 2023
31a60f8
fix typing
jcjaskula-aws Nov 21, 2023
0b02f14
add index and pop tests
jcjaskula-aws Nov 21, 2023
0a7985e
fix code coverage
jcjaskula-aws Nov 21, 2023
c75f331
move unitary matrices
jcjaskula-aws Nov 21, 2023
df1b1a9
use a subindex in MomentKey
jcjaskula-aws Nov 23, 2023
daa9cd9
print global phase integration
jcjaskula-aws Nov 24, 2023
9e5f7dc
fix docstrings
jcjaskula-aws Nov 24, 2023
aa46064
fix circuits zero total global phase
jcjaskula-aws Nov 24, 2023
590d9c8
fix edge cases
jcjaskula-aws Nov 24, 2023
dec59aa
fix to_unitary
jcjaskula-aws Nov 24, 2023
ef91d3d
temporary fix that checks classname
jcjaskula-aws Nov 25, 2023
dfdecfe
clean up test conditions
jcjaskula-aws Nov 26, 2023
e5eaa21
change logic according to feedback
jcjaskula-aws Nov 28, 2023
b8f0f33
update docstring
jcjaskula-aws Nov 28, 2023
244d708
clean tests
jcjaskula-aws Nov 28, 2023
c185e41
update tests
jcjaskula-aws Nov 28, 2023
4efb8bc
replace control symbols
jcjaskula-aws Nov 30, 2023
ccb81fa
use box drawing characters
jcjaskula-aws Nov 30, 2023
4aa7545
Revert "use box drawing characters"
jcjaskula-aws Dec 1, 2023
c2291f8
Revert "replace control symbols"
jcjaskula-aws Dec 1, 2023
9386bca
simplify all gphase case
jcjaskula-aws Dec 1, 2023
ecbdff1
change preprare_y_axis function name
jcjaskula-aws Dec 3, 2023
696974d
Merge branch 'main' into jcjaskula-aws/add_u_gate
jcjaskula-aws Dec 11, 2023
ad1053f
create an helper function to compute the global phase
jcjaskula-aws Dec 11, 2023
cb6baac
make control_basis_state more explicit
jcjaskula-aws Dec 11, 2023
52ce20d
add comment and clean grouping
jcjaskula-aws Dec 11, 2023
d61a0d1
add test_only_neg_control_qubits
jcjaskula-aws Dec 11, 2023
b14c03b
parametrize test_one_gate_with_global_phase
jcjaskula-aws Dec 12, 2023
095fb68
reformat
jcjaskula-aws Dec 12, 2023
8ebb0ce
change to printing with fixed precision
jcjaskula-aws Dec 12, 2023
35a92cd
Merge branch 'main' into jcjaskula-aws/add_u_gate
jcjaskula-aws Dec 18, 2023
0626370
Merge branch 'main' into jcjaskula-aws/add_u_gate
jcjaskula-aws Dec 18, 2023
304a01d
Merge branch 'main' into jcjaskula-aws/add_u_gate
jcjaskula-aws Dec 20, 2023
b6e9563
fix docstring
jcjaskula-aws Dec 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/braket/circuits/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,118 @@ def phaseshift(
Gate.register_gate(PhaseShift)


class U(TripleAngledGate):
"""Parameterized primitive gate for OpenQASM simulator
jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved

jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
Args:
angle_1 (Union[FreeParameterExpression, float]): theta angle in radians.
angle_2 (Union[FreeParameterExpression, float]): phi angle in radians.
angle_3 (Union[FreeParameterExpression, float]): lambda angle in radians.
"""

def __init__(
self,
angle_1: Union[FreeParameterExpression, float],
angle_2: Union[FreeParameterExpression, float],
angle_3: Union[FreeParameterExpression, float],
Comment on lines +1420 to +1422
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add defaults for this gate as we did with MS? That way we can users can define a u2 gate by only providing relevant params.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be tricky since only the first gate would have a default, so maybe we circle back to this in another pr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we just add documentation that setting angle_1 to pi/2 is equivalent to U2

Copy link
Contributor Author

@jcjaskula-aws jcjaskula-aws Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like u2/u3 are defined with a combination of gphase and U here. I like the idea to define u_i / update the docstring in another PR.

):
super().__init__(
angle_1=angle_1,
angle_2=angle_2,
angle_3=angle_3,
qubit_count=None,
ascii_symbols=[_multi_angled_ascii_characters("U", angle_1, angle_2, angle_3)],
)

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

def to_matrix(self) -> np.ndarray:
"""
Generate parameterized Unitary matrix.
https://openqasm.com/language/gates.html#built-in-gates

jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
Returns:
np.ndarray: U Matrix
"""
theta = self.angle_1
phi = self.angle_2
lam = self.angle_3
jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
return np.array(
[
[
np.cos(theta / 2),
-np.exp(1j * lam) * np.sin(theta / 2),
],
[
np.exp(1j * phi) * np.sin(theta / 2),
np.exp(1j * (phi + lam)) * np.cos(theta / 2),
],
]
)

def adjoint(self) -> list[Gate]:
return [U(self.angle_1, np.pi - self.angle_3, np.pi - self.angle_2)]
jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved

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

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

@staticmethod
@circuit.subroutine(register=True)
def u(
target: QubitInput,
angle_1: Union[FreeParameterExpression, float],
angle_2: Union[FreeParameterExpression, float],
angle_3: Union[FreeParameterExpression, float],
*,
control: Optional[QubitSetInput] = None,
control_state: Optional[BasisStateInput] = None,
power: float = 1,
) -> Iterable[Instruction]:
"""Registers this function into the circuit class.

jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
Args:
target1 (QubitInput): Target qubit 1 index.
jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
angle_1 (Union[FreeParameterExpression, float]): theta angle in radians.
angle_2 (Union[FreeParameterExpression, float]): phi angle in radians.
angle_3 (Union[FreeParameterExpression, float]): lambda angle 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:
Iterable[Instruction]: MS instruction.

Examples:
>>> circ = Circuit().ms(0, 1, 0.15, 0.34)
"""
return [
Instruction(
U(angle_1, angle_2, angle_3),
target=qubit,
control=control,
control_state=control_state,
power=power,
)
for qubit in QubitSet(target)
]


Gate.register_gate(U)


# Two qubit gates #


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 @@ -55,6 +55,7 @@
"rx": braket_gates.Rx,
"ry": braket_gates.Ry,
"rz": braket_gates.Rz,
"U": braket_gates.U,
"swap": braket_gates.Swap,
"iswap": braket_gates.ISwap,
"pswap": braket_gates.PSwap,
Expand Down
18 changes: 17 additions & 1 deletion test/unit_tests/braket/circuits/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class TripleAngle:
(Gate.Rx, "rx", ir.Rx, [SingleTarget, Angle], {}),
(Gate.Ry, "ry", ir.Ry, [SingleTarget, Angle], {}),
(Gate.Rz, "rz", ir.Rz, [SingleTarget, Angle], {}),
(Gate.U, "u", None, [SingleTarget, TripleAngle], {}),
jcjaskula-aws marked this conversation as resolved.
Show resolved Hide resolved
(Gate.CNot, "cnot", ir.CNot, [SingleTarget, SingleControl], {}),
(Gate.CV, "cv", ir.CV, [SingleTarget, SingleControl], {}),
(Gate.CCNot, "ccnot", ir.CCNot, [SingleTarget, DoubleControl], {}),
Expand Down Expand Up @@ -121,6 +122,7 @@ class TripleAngle:
Gate.Rx,
Gate.Ry,
Gate.Rz,
Gate.U,
Gate.PhaseShift,
Gate.PSwap,
Gate.XX,
Expand Down Expand Up @@ -434,6 +436,18 @@ def test_ir_gate_level(testclass, subroutine_name, irclass, irsubclasses, kwargs
OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL),
"rz(0.17) $4;",
),
(
Gate.U(angle_1=0.17, angle_2=3.45, angle_3=5.21),
[4],
OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.VIRTUAL),
"U(0.17, 3.45, 5.21) q[4];",
),
(
Gate.U(angle_1=0.17, angle_2=3.45, angle_3=5.21),
[4],
OpenQASMSerializationProperties(qubit_reference_type=QubitReferenceType.PHYSICAL),
"U(0.17, 3.45, 5.21) $4;",
),
(
Gate.XX(angle=0.17),
[4, 5],
Expand Down Expand Up @@ -859,6 +873,8 @@ def test_gate_subroutine(testclass, subroutine_name, irclass, irsubclasses, kwar
subroutine_input = {"target": multi_targets}
if Angle in irsubclasses:
subroutine_input.update(angle_valid_input())
if TripleAngle in irsubclasses:
subroutine_input.update(triple_angle_valid_input())
assert subroutine(**subroutine_input) == Circuit(instruction_list)


Expand Down Expand Up @@ -925,7 +941,7 @@ def test_large_unitary():

@pytest.mark.parametrize("gate", parameterizable_gates)
def test_bind_values(gate):
triple_angled = gate.__name__ in ("MS",)
triple_angled = gate.__name__ in ("MS", "U")
num_params = 3 if triple_angled else 1
thetas = [FreeParameter(f"theta_{i}") for i in range(num_params)]
mapping = {f"theta_{i}": i for i in range(num_params)}
Expand Down
Loading