Skip to content

Commit

Permalink
Basis ordering (#237)
Browse files Browse the repository at this point in the history
* first working version

* puts all the tests in the same class

* making bots happy

* updates autosummary

* One extra test

* updates changelog

* Fixes error message

* Update thewalrus/symplectic.py

Co-authored-by: Josh Izaac <[email protected]>

* Update thewalrus/symplectic.py

Co-authored-by: Josh Izaac <[email protected]>

* Update thewalrus/symplectic.py

Co-authored-by: Josh Izaac <[email protected]>
  • Loading branch information
nquesada and josh146 committed Apr 21, 2021
1 parent ca55d20 commit 185afcc
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

* Adds new functions `total_photon_number_distribution` and `characteristic_function` to study properties of the total photon number distribution of a `k` identical lossy squeezers. [#230](https://github.com/XanaduAI/thewalrus/pull/230/)

* Adds new functions `xxpp_to_xpxp` and `xpxp_to_xxpp` in the `symplectic` module to swap the ordering of the quadrature operators in vectors and matrices. [#237](https://github.com/XanaduAI/thewalrus/pull/237/)


### Improvements

Expand Down
52 changes: 52 additions & 0 deletions thewalrus/symplectic.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
reduced_state
is_symplectic
sympmat
xxpp_to_xpxp
xpxp_to_xxpp
Gaussian states
---------------
Expand Down Expand Up @@ -361,3 +363,53 @@ def autonne(A, rtol=1e-05, atol=1e-08, svd_order=True):
if svd_order:
return (vals[n : 2 * n])[::-1], U[:, ::-1]
return vals[n : 2 * n], U

def xxpp_to_xpxp(S):
"""Permutes the entries of the input from xxpp ordering to xpxp ordering.
Args:
S (array): input even dimensional square matrix or array
Returns:
(array): permuted matrix or array
"""
shape = S.shape
n = shape[0]

if n % 2 != 0:
raise ValueError("The input array is not even-dimensional")

n = n // 2
ind = np.arange(2 * n).reshape(2, -1).T.flatten()

if len(shape) == 2:
if shape[0] != shape[1]:
raise ValueError("The input matrix is not square")
return S[:, ind][ind]

return S[ind]

def xpxp_to_xxpp(S):
"""Permutes the entries of the input from xpxp ordering to xxpp ordering.
Args:
S (array): input even dimensional square matrix or vector
Returns:
(array): permuted matrix or vector
"""
shape = S.shape
n = shape[0]

if n % 2 != 0:
raise ValueError("The input array is not even-dimensional")

n = n // 2
ind = np.arange(2 * n).reshape(-1, 2).T.flatten()

if len(shape) == 2:
if shape[0] != shape[1]:
raise ValueError("The input matrix is not square")
return S[:, ind][ind]

return S[ind]
54 changes: 54 additions & 0 deletions thewalrus/tests/test_symplectic.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,57 @@ def test_autonne_error():
A = np.random.rand(n, m)
with pytest.raises(ValueError, match="The input matrix is not symmetric"):
symplectic.autonne(A)


class TestPhaseSpaceFunctions:
"""Tests for the shared phase space operations"""

def test_means_changebasis(self):
"""Test the change of basis function applied to vectors. This function
converts from xp to symmetric ordering, and vice versa."""
means_xp = np.array([1, 2, 3, 4, 5, 6])
means_symmetric = np.array([1, 4, 2, 5, 3, 6])

assert np.all(symplectic.xxpp_to_xpxp(means_xp) == means_symmetric)
assert np.all(symplectic.xpxp_to_xxpp(means_symmetric) == means_xp)

def test_cov_changebasis(self):
"""Test the change of basis function applied to matrices. This function
converts from xp to symmetric ordering, and vice versa."""
cov_xp = np.array(
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
)

cov_symmetric = np.array(
[[0, 2, 1, 3], [8, 10, 9, 11], [4, 6, 5, 7], [12, 14, 13, 15]]
)

assert np.all(symplectic.xxpp_to_xpxp(cov_xp) == cov_symmetric)
assert np.all(symplectic.xpxp_to_xxpp(cov_symmetric) == cov_xp)

@pytest.mark.parametrize("fun", [symplectic.xxpp_to_xpxp, symplectic.xpxp_to_xxpp])
def test_change_basis_raises_not_square(self, fun):
"""Test correct error is raised when a non-square matrix is passed"""
A = np.random.rand(4,6)
with pytest.raises(ValueError, match="The input matrix is not square"):
fun(A)

@pytest.mark.parametrize("fun", [symplectic.xxpp_to_xpxp, symplectic.xpxp_to_xxpp])
@pytest.mark.parametrize("dim", [1, 2])
def test_change_basis_raises_not_even(self, fun, dim):
"""Test correct error is raised when a non-even-dimensional array is passed"""
size = (5,) * dim
A = np.random.rand(*size)
with pytest.raises(ValueError, match="The input array is not even-dimensional"):
fun(A)

@pytest.mark.parametrize("dim", [2, 4, 6, 8])
def test_functional_inverse(self, dim):
"""Check that xxpp_to_xpxp is the inverse of xpxp_to_xxpp and viceversa"""
M = np.random.rand(dim, dim)
assert np.all(M == symplectic.xxpp_to_xpxp(symplectic.xpxp_to_xxpp(M)))
assert np.all(M == symplectic.xpxp_to_xxpp(symplectic.xxpp_to_xpxp(M)))

v = np.random.rand(dim)
assert np.all(v == symplectic.xxpp_to_xpxp(symplectic.xpxp_to_xxpp(v)))
assert np.all(v == symplectic.xpxp_to_xxpp(symplectic.xxpp_to_xpxp(v)))

0 comments on commit 185afcc

Please sign in to comment.