Skip to content

Commit

Permalink
Refactor tests for optional extras
Browse files Browse the repository at this point in the history
  • Loading branch information
thangleiter committed Jul 3, 2020
1 parent fefd8cb commit 37c7409
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 94 deletions.
36 changes: 20 additions & 16 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
dist: xenial

language: python

python:
- '3.5'
- '3.6'
- '3.7'
- '3.8'
- 3.5
- 3.6
- 3.7
- 3.8
env:
- INSTALL_EXTRAS=[plotting,bloch_sphere_visualization,fancy_progressbar,tests]
- INSTALL_EXTRAS=[bloch_sphere_visualization,fancy_progressbar,tests]
- INSTALL_EXTRAS=[plotting,bloch_sphere_visualization,tests]
- INSTALL_EXTRAS=[plotting,fancy_progressbar,tests]

#use container based infrastructure
sudo: false

#these directories are persistent
cache: pip

#manually install these dependencies so that qutip can be installed via pip
before_install:
- pip install numpy scipy cython

install:
- wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda config --append channels conda-forge
- conda info -a
- conda env create -f ./environment.yml
- source activate filter_functions
- pip install .[all]
- pip install .$INSTALL_EXTRAS

script:
- coverage run --rcfile=coverage.ini -m pytest
Expand Down
11 changes: 11 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@
#
# Contact email: tobias.hangleiter@rwth-aachen.de
# =============================================================================

try:
import qutip
except ImportError:
qutip = None

try:
import matplotlib
matplotlib.use('Agg')
except ImportError:
matplotlib = None
28 changes: 22 additions & 6 deletions tests/test_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
from itertools import product

import numpy as np
import qutip as qt
import pytest
from sparse import COO

import filter_functions as ff
from tests import testutil

from . import qutip


class BasisTest(testutil.TestCase):

Expand All @@ -42,14 +44,11 @@ def test_basis_constructor(self):
_ = ff.Basis(1)

# All elements should be either sparse, Qobj, or ndarray
elems = [ff.util.paulis[1], qt.sigmay(), qt.qeye(2).data,
COO.from_numpy(ff.util.paulis[3]), [[0, 1], [1, 0]]]
elems = [ff.util.paulis[1], COO.from_numpy(ff.util.paulis[3]),
[[0, 1], [1, 0]]]
with self.assertRaises(TypeError):
_ = ff.Basis(elems)

# Excluding the fast_csr element should work
self.assertEqual(ff.Basis.pauli(1), ff.Basis(elems[:-1]))

# Too many elements
with self.assertRaises(ValueError):
_ = ff.Basis(testutil.rng.randn(5, 2, 2))
Expand Down Expand Up @@ -328,3 +327,20 @@ def test_control_matrix(self):
elif i == 1 and j == 1:
# base traceless, nopers traceless
self.assertTrue(np.allclose(R[:, 0], 0))


@pytest.mark.skipif(
qutip is None,
reason='Skipping qutip compatibility test for build without qutip')
class QutipCompatibilityTest(testutil.TestCase):

def test_constructor(self):
"""Test if can create basis from qutip objects."""

elems_qutip = [qutip.sigmay(), qutip.qeye(2).data]
elems_np = [qutip.sigmay().full(), qutip.qeye(2).full()]

basis_qutip = ff.Basis(elems_qutip)
basis_np = ff.Basis(elems_np)

self.assertArrayEqual(basis_qutip, basis_np)
72 changes: 72 additions & 0 deletions tests/test_extras.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# =============================================================================
# filter_functions
# Copyright (C) 2019 Quantum Technology Group, RWTH Aachen University
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Contact email: tobias.hangleiter@rwth-aachen.de
# =============================================================================
"""
This module tests if optional extras are handled correctly.
"""
import os

import pytest
from numpy import ndarray

from tests import testutil

all_extras = ['fancy_progressbar', 'plotting', 'bloch_sphere_visualization']


class MissingExtrasTest(testutil.TestCase):

@pytest.mark.skipif(
'fancy_progressbar' in os.environ.get('INSTALL_EXTRAS', all_extras),
reason='Skipping tests for missing fancy progressbar extra in build with requests') # noqa
def test_fancy_progressbar_not_available(self):
from filter_functions import util
from tqdm import tqdm
self.assertEqual(util._NOTEBOOK_NAME, '')
self.assertIs(tqdm, util._tqdm)

@pytest.mark.skipif(
'plotting' in os.environ.get('INSTALL_EXTRAS', all_extras),
reason='Skipping tests for missing plotting extra in build with matplotlib') # noqa
def test_plotting_not_available(self):
with self.assertRaises(ModuleNotFoundError):
from filter_functions import plotting

@pytest.mark.skipif(
'bloch_sphere_visualization' in os.environ.get('INSTALL_EXTRAS', all_extras), # noqa
reason='Skipping tests for missing bloch sphere visualization tests in build with qutip') # noqa
def test_bloch_sphere_visualization_not_available(self):

with self.assertWarns(UserWarning):
from filter_functions import plotting

with self.assertRaises(RuntimeError):
plotting.get_bloch_vector(testutil.rng.randn(10, 2))

with self.assertRaises(RuntimeError):
plotting.init_bloch_sphere()

with self.assertRaises(RuntimeError):
plotting.plot_bloch_vector_evolution(
testutil.rand_pulse_sequence(2))

from filter_functions import types
self.assertIs(types.State, ndarray)
self.assertIs(types.Operator, ndarray)
105 changes: 56 additions & 49 deletions tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,69 +21,31 @@
"""
This module tests the plotting functionality of the package.
"""
import matplotlib

# Needs to be executed before the pyplot import
matplotlib.use('Agg')

import string
from random import sample

import matplotlib.pyplot as plt
import numpy as np
import pytest
import qutip as qt

import filter_functions as ff
from filter_functions import plotting
from tests import testutil

from . import qutip

plotting = pytest.importorskip(
'filter_functions.plotting',
reason='Skipping plotting tests for build without matplotlib',
)
if plotting is not None:
import matplotlib.pyplot as plt

simple_pulse = testutil.rand_pulse_sequence(2, 1, 1, 1, btype='Pauli')
complicated_pulse = testutil.rand_pulse_sequence(2, 100, 3, 3)
two_qubit_pulse = testutil.rand_pulse_sequence(4, 1, 1, 6, btype='Pauli')


class PlottingTest(testutil.TestCase):

def test_get_bloch_vector(self):
states = [qt.rand_ket(2) for _ in range(10)]
bloch_vectors_qt = plotting.get_bloch_vector(states)
bloch_vectors_np = plotting.get_bloch_vector([state.full()
for state in states])

for bv_qt, bv_np in zip(bloch_vectors_qt, bloch_vectors_np):
self.assertArrayAlmostEqual(bv_qt, bv_np)

def test_get_states_from_prop(self):
P = testutil.rand_unit(2, 10)
Q = np.empty((11, 2, 2), dtype=complex)
Q[0] = np.identity(2)
for i in range(10):
Q[i+1] = P[i] @ Q[i]

psi0 = qt.rand_ket(2)
states_piecewise = plotting.get_states_from_prop(P, psi0, 'piecewise')
states_total = plotting.get_states_from_prop(Q[1:], psi0, 'total')
self.assertArrayAlmostEqual(states_piecewise, states_total)

def test_plot_bloch_vector_evolution(self):
# Call with default args
b = plotting.plot_bloch_vector_evolution(simple_pulse)
# Call with custom args
b = plotting.init_bloch_sphere(background=True)
b = plotting.plot_bloch_vector_evolution(simple_pulse,
psi0=qt.basis(2, 1), b=b,
n_samples=50, show=False,
return_Bloch=True)

b = plotting.plot_bloch_vector_evolution(complicated_pulse)

# Check exceptions being raised
with self.assertRaises(ValueError):
plotting.plot_bloch_vector_evolution(two_qubit_pulse)

plt.close('all')

def test_plot_pulse_train(self):
# Call with default args
fig, ax, leg = plotting.plot_pulse_train(simple_pulse)
Expand Down Expand Up @@ -292,12 +254,12 @@ def test_plot_error_transfer_matrix(self):
fig, grid = plotting.plot_error_transfer_matrix(
complicated_pulse, S=S, omega=omega,
n_oper_identifiers=n_oper_identifiers, basis_labels=basis_labels,
basis_labelsize=4, linthresh=1e-4, cmap=matplotlib.cm.jet
basis_labelsize=4, linthresh=1e-4, cmap=plt.cm.jet
)
fig, grid = plotting.plot_error_transfer_matrix(
U=U[n_oper_inds], n_oper_identifiers=n_oper_identifiers,
basis_labels=basis_labels, basis_labelsize=4, linthresh=1e-4,
cmap=matplotlib.cm.jet
cmap=plt.cm.jet
)

# neither U nor all of pulse, S, omega given
Expand Down Expand Up @@ -338,3 +300,48 @@ def S(omega):

n, infids = ff.infidelity(simple_pulse, S, {}, test_convergence=True)
fig, ax = plotting.plot_infidelity_convergence(n, infids)


@pytest.mark.skipif(
qutip is None,
reason='Skipping bloch sphere visualization tests for build without qutip')
class BlochSphereVisualizationTest(testutil.TestCase):

def test_get_bloch_vector(self):
states = [qutip.rand_ket(2) for _ in range(10)]
bloch_vectors_qutip = plotting.get_bloch_vector(states)
bloch_vectors_np = plotting.get_bloch_vector([state.full()
for state in states])

for bv_qutip, bv_np in zip(bloch_vectors_qutip, bloch_vectors_np):
self.assertArrayAlmostEqual(bv_qutip, bv_np)

def test_get_states_from_prop(self):
P = testutil.rand_unit(2, 10)
Q = np.empty((11, 2, 2), dtype=complex)
Q[0] = np.identity(2)
for i in range(10):
Q[i+1] = P[i] @ Q[i]

psi0 = qutip.rand_ket(2)
states_piecewise = plotting.get_states_from_prop(P, psi0, 'piecewise')
states_total = plotting.get_states_from_prop(Q[1:], psi0, 'total')
self.assertArrayAlmostEqual(states_piecewise, states_total)

def test_plot_bloch_vector_evolution(self):
# Call with default args
b = plotting.plot_bloch_vector_evolution(simple_pulse)
# Call with custom args
b = plotting.init_bloch_sphere(background=True)
b = plotting.plot_bloch_vector_evolution(simple_pulse,
psi0=qutip.basis(2, 1), b=b,
n_samples=50, show=False,
return_Bloch=True)

b = plotting.plot_bloch_vector_evolution(complicated_pulse)

# Check exceptions being raised
with self.assertRaises(ValueError):
plotting.plot_bloch_vector_evolution(two_qubit_pulse)

plt.close('all')
10 changes: 6 additions & 4 deletions tests/test_precision.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@
"""

import numpy as np
import qutip as qt

import filter_functions as ff
from filter_functions import analytic, numeric
from filter_functions import analytic, numeric, util
from tests import testutil


Expand Down Expand Up @@ -192,6 +191,9 @@ def test_liouville_representation(self):

def test_diagonalization_cnot(self):
"""CNOT"""
cnot_mat = np.block([[util.paulis[0], np.zeros((2, 2))],
[np.zeros((2, 2)), util.paulis[1]]])

subspace_c_opers = testutil.subspace_opers
subspace_n_opers = subspace_c_opers
c_opers = testutil.opers
Expand All @@ -212,12 +214,12 @@ def test_diagonalization_cnot(self):
cnot_subspace.diagonalize()

phase_eq = ff.util.oper_equiv(cnot_subspace.total_Q[1:5, 1:5],
qt.cnot(), eps=1e-9)
cnot_mat, eps=1e-9)

self.assertTrue(phase_eq[0])

phase_eq = ff.util.oper_equiv(
cnot.total_Q[np.ix_(*subspace)][1:5, 1:5], qt.cnot(), eps=1e-9)
cnot.total_Q[np.ix_(*subspace)][1:5, 1:5], cnot_mat, eps=1e-9)

self.assertTrue(phase_eq[0])

Expand Down
2 changes: 1 addition & 1 deletion tests/test_sequencing.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
This module tests the concatenation functionality for PulseSequence's.
"""

from copy import copy
import string
from copy import copy
from itertools import product
from random import sample

Expand Down
Loading

0 comments on commit 37c7409

Please sign in to comment.