-
Notifications
You must be signed in to change notification settings - Fork 658
Improved decomposition of DiagonalQubitUnitary
#7370
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
Open
dwierichs
wants to merge
62
commits into
master
Choose a base branch
from
better-diag-decomp
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
d6545e8
New decompostion; tests; changelog; dev comments; docs.
dwierichs dcbcd3f
format, bit_count
dwierichs 98490c6
update
dwierichs 2e9a1e2
Merge branch 'master' into pcphase-decomp
dwierichs d8ce851
extract controlled phase shift subroutine
dwierichs 3aa0519
docstring
dwierichs e2b1a89
merge
dwierichs a0e041a
formatting
dwierichs 3964084
Merge branch 'master' into pcphase-decomp
dwierichs 0ab7fd6
[skip ci] new numbering
dwierichs ba40c67
Merge branch 'master' into pcphase-decomp
dwierichs 82a079c
tiny
dwierichs 07c4093
numbering is not easy in sphinx RST
dwierichs 8bcec72
first review
dwierichs 8d45023
some doc progress?
dwierichs f9ab42b
?
dwierichs f3d7b16
table?
dwierichs 7e1dd75
table!
dwierichs 575291a
outsource algo description to markdown file. replace docstring with e…
dwierichs 282839a
polish
dwierichs f09eda7
polish md
dwierichs b7d728b
align test
dwierichs f33251b
align test
dwierichs 2afde61
polish
dwierichs 4f99267
whitespace
dwierichs 5247589
polish
dwierichs f8a842e
Apply suggestions from code review
dwierichs ebd2bd1
link
dwierichs 86d3ad2
Merge branch 'master' into pcphase-decomp
dwierichs 8a74f7f
changelog
dwierichs e82409d
start
dwierichs dfd963b
docstring
dwierichs 8e67cb9
conclude
dwierichs 50f1274
merge
dwierichs c1685e1
revert unrelated
dwierichs ee6e4e1
changelog
dwierichs b46eefd
Merge branch 'master' into selectpaulirot-fwh
dwierichs 98e4cc7
start
dwierichs 3596a3f
black
dwierichs 52d9e0d
n=0 case
dwierichs d69dca5
changelog
dwierichs 0f11320
SelectPauliRot batching
dwierichs 1f4c588
merge
dwierichs 2a09b58
SelectPauliRot tests
dwierichs ec49c5e
gray code speed up
dwierichs 7a10bef
merge
dwierichs d46921c
merge Uniformly controlled rotation PR in
dwierichs 3c96fc0
test dependency fix
dwierichs 79369cd
actualy PR contrib
dwierichs 4089d47
Merge branch 'master' into selectpaulirot-fwh
dwierichs f75b4d4
review
dwierichs 1a96b81
Merge branch 'master' into selectpaulirot-fwh
dwierichs 6550b0a
Merge branch 'master' into selectpaulirot-fwh
dwierichs 6b05fde
seed
dwierichs 79cc670
Apply suggestions from code review
dwierichs ce03157
Merge branch 'selectpaulirot-fwh' into better-diag-decomp
dwierichs ac96fab
merge
dwierichs 9990bb1
docstring improvement
dwierichs 5f43940
Merge branch 'master' into better-diag-decomp
dwierichs 6d205c7
empty
dwierichs b77349a
review
dwierichs 6a6aab5
merge
dwierichs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -641,27 +641,24 @@ def test_decomposition_single_qubit(self): | |
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0]).decomposition() | ||
|
||
ph = np.exp(3j * np.pi / 4) | ||
for dec in (decomp, decomp2): | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.eye(2) * ph, 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(np.pi / 2, 0)) | ||
qml.assert_equal(decomp[0], qml.RZ(np.pi / 2, 0)) | ||
qml.assert_equal(decomp[1], qml.GlobalPhase(-3 * np.pi / 4, 0)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that the tests never actually test that the matrix of the original op and the matrix of the decomposed sequence are the same, can you add them? |
||
|
||
def test_decomposition_single_qubit_broadcasted(self): | ||
"""Test that a broadcasted single-qubit DiagonalQubitUnitary is decomposed correctly.""" | ||
D = np.stack( | ||
[[1j, -1], np.exp(1j * np.array([np.pi / 8, -np.pi / 8])), [1j, -1j], [-1, -1]] | ||
) | ||
angles = np.array([np.pi / 2, -np.pi / 4, -np.pi, 0]) | ||
D = np.exp(1j * np.pi * np.array([[1 / 2, 1], [1 / 8, -1 / 8], [1 / 2, -1 / 2], [1, 1]])) | ||
|
||
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0]).decomposition() | ||
|
||
ph = [np.exp(3j * np.pi / 4), 1, 1, -1] | ||
angles = np.array([1 / 2, -1 / 4, -1, 0]) * np.pi | ||
global_angles = np.array([3 / 4, 0, 0, 1]) * np.pi | ||
for dec in (decomp, decomp2): | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.array([np.eye(2) * p for p in ph]), 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(angles, 0)) | ||
qml.assert_equal(decomp[0], qml.RZ(angles, 0)) | ||
qml.assert_equal(decomp[1], qml.GlobalPhase(-global_angles, 0)) | ||
|
||
def test_decomposition_two_qubits(self): | ||
"""Test that a two-qubit DiagonalQubitUnitary is decomposed correctly.""" | ||
|
@@ -670,12 +667,13 @@ def test_decomposition_two_qubits(self): | |
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0, 1]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0, 1]).decomposition() | ||
|
||
angles = np.array([-2, 0.5]) | ||
new_D = np.exp(1j * np.array([0, 3 / 4])) | ||
|
||
for dec in (decomp, decomp2): | ||
assert len(dec) == 4 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.eye(2) * np.exp(0.375j), 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(-0.75, 1)) | ||
qml.assert_equal(decomp[2], qml.RZ(0.75, 0)) | ||
qml.assert_equal(decomp[3], qml.IsingZZ(-1.25, [0, 1])) | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.SelectPauliRot(angles, [0], target_wire=1)) | ||
qml.assert_equal(decomp[1], qml.DiagonalQubitUnitary(new_D, wires=[0])) | ||
|
||
def test_decomposition_two_qubits_broadcasted(self): | ||
"""Test that a broadcasted two-qubit DiagonalQubitUnitary is decomposed correctly.""" | ||
|
@@ -684,14 +682,13 @@ def test_decomposition_two_qubits_broadcasted(self): | |
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0, 1]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0, 1]).decomposition() | ||
|
||
angles = [[-0.75, -0.8, 0.65], [0.75, -2.4, -0.55], [-1.25, 0.4, -1.35]] | ||
ph = [np.exp(1j * 0.375), np.exp(1j * 0.9), np.exp(1j * 0.475)] | ||
angles = np.array([[-2, 0.5], [-0.4, -1.2], [-0.7, 2.0]]) | ||
new_D = np.exp(1j * np.array([[0, 3 / 4], [2.1, -0.3], [0.75, 0.2]])) | ||
|
||
for dec in (decomp, decomp2): | ||
assert len(dec) == 4 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.array([np.eye(2) * p for p in ph]), 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(angles[0], 1)) | ||
qml.assert_equal(decomp[2], qml.RZ(angles[1], 0)) | ||
qml.assert_equal(decomp[3], qml.IsingZZ(angles[2], [0, 1])) | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.SelectPauliRot(angles, [0], target_wire=1)) | ||
qml.assert_equal(decomp[1], qml.DiagonalQubitUnitary(new_D, wires=[0])) | ||
|
||
def test_decomposition_three_qubits(self): | ||
"""Test that a three-qubit DiagonalQubitUnitary is decomposed correctly.""" | ||
|
@@ -700,16 +697,12 @@ def test_decomposition_three_qubits(self): | |
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0, 1, 2]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0, 1, 2]).decomposition() | ||
|
||
angles = np.array([-2, 0.5, -0.1, 1.7]) | ||
new_D = np.exp(1j * np.array([0, 3 / 4, 0.15, 1.45])) | ||
for dec in (decomp, decomp2): | ||
assert len(dec) == 8 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.eye(2) * np.exp(0.5875j), 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(0.025, 2)) | ||
qml.assert_equal(decomp[2], qml.RZ(1.025, 1)) | ||
qml.assert_equal(decomp[3], qml.IsingZZ(-1.075, [1, 2])) | ||
qml.assert_equal(decomp[4], qml.RZ(0.425, 0)) | ||
qml.assert_equal(decomp[5], qml.IsingZZ(-0.775, [0, 2])) | ||
qml.assert_equal(decomp[6], qml.IsingZZ(-0.275, [0, 1])) | ||
qml.assert_equal(decomp[7], qml.MultiRZ(-0.175, [0, 1, 2])) | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.SelectPauliRot(angles, [0, 1], target_wire=2)) | ||
qml.assert_equal(decomp[1], qml.DiagonalQubitUnitary(new_D, wires=[0, 1])) | ||
|
||
def test_decomposition_three_qubits_broadcasted(self): | ||
"""Test that a broadcasted three-qubit DiagonalQubitUnitary is decomposed correctly.""" | ||
|
@@ -723,26 +716,12 @@ def test_decomposition_three_qubits_broadcasted(self): | |
decomp = qml.DiagonalQubitUnitary.compute_decomposition(D, [0, 1, 2]) | ||
decomp2 = qml.DiagonalQubitUnitary(D, wires=[0, 1, 2]).decomposition() | ||
|
||
angles = [ | ||
[0.025, -0.55], | ||
[1.025, -0.75], | ||
[-1.075, -0.75], | ||
[0.425, 0.3], | ||
[-0.775, 0.4], | ||
[-0.275, 0.5], | ||
[-0.175, 0.1], | ||
] | ||
ph = [np.exp(0.5875j), np.exp(0.625j)] | ||
angles = np.array([[-2, 0.5, -0.1, 1.7], [-0.8, 0.5, -1.8, -0.1]]) | ||
new_D = np.exp(1j * np.array([[0, 3 / 4, 0.15, 1.45], [0.6, 0.35, 1.4, 0.15]])) | ||
for dec in (decomp, decomp2): | ||
assert len(dec) == 8 | ||
qml.assert_equal(decomp[0], qml.QubitUnitary(np.array([np.eye(2) * p for p in ph]), 0)) | ||
qml.assert_equal(decomp[1], qml.RZ(angles[0], 2)) | ||
qml.assert_equal(decomp[2], qml.RZ(angles[1], 1)) | ||
qml.assert_equal(decomp[3], qml.IsingZZ(angles[2], [1, 2])) | ||
qml.assert_equal(decomp[4], qml.RZ(angles[3], 0)) | ||
qml.assert_equal(decomp[5], qml.IsingZZ(angles[4], [0, 2])) | ||
qml.assert_equal(decomp[6], qml.IsingZZ(angles[5], [0, 1])) | ||
qml.assert_equal(decomp[7], qml.MultiRZ(angles[6], [0, 1, 2])) | ||
assert len(dec) == 2 | ||
qml.assert_equal(decomp[0], qml.SelectPauliRot(angles, [0, 1], target_wire=2)) | ||
qml.assert_equal(decomp[1], qml.DiagonalQubitUnitary(new_D, wires=[0, 1])) | ||
|
||
@pytest.mark.parametrize("n", [1, 2, 3]) | ||
def test_decomposition_matrix_match(self, n, seed): | ||
|
@@ -775,7 +754,7 @@ def test_decomposition_matrix_match_broadcasted(self, n, seed): | |
assert qml.math.allclose(orig_mat, decomp_mat2) | ||
|
||
@pytest.mark.parametrize( | ||
"dtype", [np.float64, np.float32, np.int64, np.int32, np.complex128, np.complex64] | ||
"dtype", [np.float64, np.float32, np.int64, np.int32, np.int16, np.complex128, np.complex64] | ||
) | ||
def test_decomposition_cast_to_complex128(self, dtype): | ||
"""Test that the parameters of decomposed operations are of the correct dtype.""" | ||
|
@@ -784,10 +763,18 @@ def test_decomposition_cast_to_complex128(self, dtype): | |
decomp1 = qml.DiagonalQubitUnitary(D, wires).decomposition() | ||
decomp2 = qml.DiagonalQubitUnitary.compute_decomposition(D, wires) | ||
|
||
assert decomp1[0].data[0].dtype == np.complex128 | ||
assert decomp2[0].data[0].dtype == np.complex128 | ||
assert all(op.data[0].dtype == np.float64 for op in decomp1[1:]) | ||
assert all(op.data[0].dtype == np.float64 for op in decomp2[1:]) | ||
r_dtype = ( | ||
np.float64 if dtype in [np.float64, np.int64, np.int32, np.complex128] else np.float32 | ||
) | ||
c_dtype = ( | ||
np.complex128 | ||
if dtype in [np.float64, np.int64, np.int32, np.complex128] | ||
else np.complex64 | ||
) | ||
assert decomp1[0].data[0].dtype == r_dtype | ||
assert decomp2[0].data[0].dtype == r_dtype | ||
assert decomp1[1].data[0].dtype == c_dtype | ||
assert decomp2[1].data[0].dtype == c_dtype | ||
|
||
def test_controlled(self): | ||
"""Test that the correct controlled operation is created when controlling a qml.DiagonalQubitUnitary.""" | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the following should be placed inside a
.. details::
section?