-
Notifications
You must be signed in to change notification settings - Fork 189
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds ops.py and its test file (#533)
* removes unused variables in test_tdmprogram * Adds ops.py and its test file * Update strawberryfields/backends/bosonicbackend/ops.py Co-authored-by: antalszava <antalszava@gmail.com> * minor updates * adds parametrizations for most tests * adds parametrizations for some tests * parametrizes all the tests * Docstrings+variable names Rewrites docstrings correct style and provides more descriptive variable names * Put tests into class * typo fix Co-authored-by: Nicolas Quesada <zeitus@gmail.com> * Adds bosonic pytest mark * Apply suggestions from code review Co-authored-by: antalszava <antalszava@gmail.com> Co-authored-by: antalszava <antalszava@gmail.com> Co-authored-by: elib20 <53090166+elib20@users.noreply.github.com>
- Loading branch information
1 parent
097dbc3
commit 98898e8
Showing
3 changed files
with
217 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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 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 |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Copyright 2021 Xanadu Quantum Technologies Inc. | ||
|
||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
|
||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
r"""Gaussian operations vectorizing commonly used operation on covariance matrices and vectors of means""" | ||
|
||
import numpy as np | ||
|
||
|
||
def chop_in_blocks_multi(m, id_to_delete): | ||
r""" | ||
Splits an array of (symmetric) matrices each into 3 blocks (``A``, ``B``, ``C``). | ||
Blocks ``A`` and ``C`` are diagonal blocks and ``B`` is the offdiagonal block. | ||
Args: | ||
m (ndarray): array of matrices | ||
id_to_delete (ndarray): array for the indices that go into ``C`` | ||
Returns: | ||
tuple: tuple of the ``A``, ``B`` and ``C`` matrices | ||
""" | ||
A = np.delete(m, id_to_delete, axis=1) | ||
A = np.delete(A, id_to_delete, axis=2) | ||
B = np.delete(m[:, :, id_to_delete], id_to_delete, axis=1) | ||
C = m[:, id_to_delete, :][:, :, id_to_delete] | ||
return (A, B, C) | ||
|
||
|
||
def chop_in_blocks_vector_multi(v, id_to_delete): | ||
r""" | ||
For an array of vectors ``v``, splits ``v`` into two arrays of vectors, | ||
``va`` and ``vb``. ``vb`` contains the components of ``v`` specified by | ||
``id_to_delete``, and ``va`` contains the remaining components. | ||
Args: | ||
v (ndarray): array of vectors | ||
id_to_delete (ndarray): array for the indices that go into vb | ||
Returns: | ||
tuple: tuple of ``(va,vb)`` vectors | ||
""" | ||
id_to_keep = np.sort(list(set(np.arange(len(v[0]))) - set(id_to_delete))) | ||
va = v[:, id_to_keep] | ||
vb = v[:, id_to_delete] | ||
return (va, vb) | ||
|
||
|
||
def reassemble_multi(A, id_to_delete): | ||
r""" | ||
For an array of matrices ``A``, creates a new array of matrices, each with | ||
dimension ``dim(A)+len(id_to_delete)``. The subspace of each new matrix | ||
specified by indices ``id_to_delete`` is set to the identity matrix, while | ||
the rest of each new matrix is filled with the matrices from ``A``. | ||
Args: | ||
m (ndarray): array of matrices | ||
id_to_delete (ndarray): array of indices in the new matrices that will | ||
be set to the identity | ||
Returns: | ||
array: array of new matrices, each filled with ``A`` and identity | ||
""" | ||
num_weights = len(A[:, 0, 0]) | ||
new_mat_dim = len(A[0]) + len(id_to_delete) | ||
ind = np.sort(list(set(np.arange(new_mat_dim)) - set(id_to_delete))) | ||
new_mat = np.tile(np.eye(new_mat_dim, dtype=complex), (num_weights, 1, 1)) | ||
new_mat[np.ix_(np.arange(new_mat.shape[0], dtype=int), ind, ind)] = A | ||
return new_mat | ||
|
||
|
||
def reassemble_vector_multi(va, id_to_delete): | ||
r""" | ||
For an array of vectors ``va``, creates a new array of vectors, each with | ||
dimension ``dim(va)+len(id_to_delete)``. The subspace of each new vector | ||
specified by indices ``id_to_delete`` is set to 0, while the rest of each | ||
new vector is filled with the vectors from ``va``. | ||
Args: | ||
va (ndarray): array of vectors | ||
id_to_delete (ndarray): array of indices in the new vectors that will | ||
be set to 0 | ||
Returns: | ||
array: array of new vectors, each filled with ``va`` and 0 | ||
""" | ||
num_weights = len(va[:, 0]) | ||
new_vec_dim = len(va[0]) + len(id_to_delete) | ||
ind = np.sort(list(set(np.arange(new_vec_dim)) - set(id_to_delete))) | ||
new_vec = np.zeros((num_weights, new_vec_dim), dtype=complex) | ||
new_vec[:, ind] = va | ||
return new_vec |
This file contains 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 |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Copyright 2021 Xanadu Quantum Technologies Inc. | ||
|
||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
|
||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
r""" | ||
Unit tests for backends.bosonicbackend.ops.py . | ||
""" | ||
|
||
import pytest | ||
|
||
import numpy as np | ||
import strawberryfields.backends.bosonicbackend.ops as ops | ||
|
||
pytestmark = pytest.mark.bosonic | ||
|
||
class TestOpsFunctions: | ||
r"""Tests all the functions inside backends.bosonicbackend.ops.py""" | ||
|
||
@pytest.mark.parametrize("reps", [1, 2, 5, 10]) | ||
def test_chop_in_blocks_multi(self, reps): | ||
r"""Checks that ops.chop_in_block_multi partitions arrays of matrices correctly""" | ||
# Create submatrices | ||
A = np.random.rand(2, 2) | ||
B = np.random.rand(2, 3) | ||
C = np.random.rand(3, 3) | ||
|
||
# Repeat them in an array | ||
Atile = np.tile(A, [reps, 1, 1]) | ||
Btile = np.tile(B, [reps, 1, 1]) | ||
Ctile = np.tile(C, [reps, 1, 1]) | ||
|
||
# Make a new block matrix out of them and repeat it | ||
m = np.block([[A, B], [B.T, C]]) | ||
m = np.tile(m, [reps, 1, 1]) | ||
|
||
# Choose to delete the indices corresponding to C | ||
id_to_delete = np.arange(2, 5, dtype=int) | ||
|
||
A2, B2, C2 = ops.chop_in_blocks_multi(m, id_to_delete) | ||
|
||
assert np.allclose(A2, Atile) | ||
assert np.allclose(B2, Btile) | ||
assert np.allclose(C2, Ctile) | ||
|
||
@pytest.mark.parametrize("reps", [1, 2, 5, 10]) | ||
def test_chop_in_blocks_vector_multi(self, reps): | ||
r"""Checks that ops.chop_in_block_vector_multi partitions arrays of vectors correctly""" | ||
|
||
# Create vectors | ||
va = np.random.rand(6) | ||
vb = np.random.rand(4) | ||
|
||
# Repeat them in an array | ||
vatile = np.tile(va, [reps, 1]) | ||
vbtile = np.tile(vb, [reps, 1]) | ||
|
||
# Make a new vector out of them and repeat it | ||
v = np.append(va, vb) | ||
v = np.tile(v, [reps, 1]) | ||
|
||
# Choose to delete the indices corresponding to C | ||
id_to_delete = np.arange(6, 10, dtype=int) | ||
|
||
va2, vb2 = ops.chop_in_blocks_vector_multi(v, id_to_delete) | ||
|
||
assert np.allclose(va2, vatile) | ||
assert np.allclose(vb2, vbtile) | ||
|
||
@pytest.mark.parametrize("id_to_delete", [[0], [0, 1], [2, 0, 1], [0, 2, 4, 5]]) | ||
def test_reassemble_multi(self, id_to_delete): | ||
r"""Checks that ops.reassemble_multi generates the correct output""" | ||
|
||
# Create matrix | ||
A = np.random.rand(2, 2) | ||
reps = np.random.randint(1, 10) | ||
Atile = np.tile(A, [reps, 1, 1]) | ||
# Create indices | ||
m = ops.reassemble_multi(Atile, id_to_delete) | ||
dim = len(A) + len(id_to_delete) | ||
id_to_keep = list(set(range(dim)) - set(id_to_delete)) | ||
id_to_keep.sort() | ||
assert m.shape == (reps, dim, dim) | ||
|
||
A2, B2, C2 = ops.chop_in_blocks_multi(m, id_to_keep) | ||
assert np.allclose(C2, Atile) | ||
assert np.allclose(B2, 0) | ||
assert np.allclose(A2, np.tile(np.eye(len(id_to_delete)), [reps, 1, 1])) | ||
|
||
@pytest.mark.parametrize("id_to_delete", [[0], [0, 1], [2, 0, 1], [0, 2, 4, 5]]) | ||
def test_reassemble_vector_multi(self, id_to_delete): | ||
r"""Checks that ops.reassemble_vector_multi generates the correct output""" | ||
# Create matrix | ||
v = np.random.rand(4) | ||
reps = np.random.randint(1, 10) | ||
vtile = np.tile(v, [reps, 1]) | ||
# Create indices | ||
m = ops.reassemble_vector_multi(vtile, id_to_delete) | ||
dim = len(v) + len(id_to_delete) | ||
id_to_keep = list(set(range(dim)) - set(id_to_delete)) | ||
id_to_keep.sort() | ||
assert m.shape == (reps, dim) | ||
|
||
va2, vb2 = ops.chop_in_blocks_vector_multi(m, id_to_keep) | ||
assert np.allclose(vb2, vtile) | ||
assert np.allclose(va2, 0) |