Skip to content
This repository has been archived by the owner on Jun 12, 2023. It is now read-only.

Commit

Permalink
Add scikit-learn dependency and add CI job without optional dependenc…
Browse files Browse the repository at this point in the history
…ies (#436)

* Add scikit-learn dependency and add CI job without optional deps

This commit adds a new ci job for running ignis tests without any
optional dependencies. There are several optional dependencies which do
not not always get installed with ignis. They are needed to enable
optional features but shouldn't be required, we've had a slew of recent
bugs around accidentally requiring these optional dependencies (see
issues #429, #422, and #312). None of these were caught in CI because we
always install all optional dependencies in CI test jobs. By adding a
new job which explicitly installs the bare minimum we're emulating what
a user does when they install just ignis.

As part of this a missing dependency was added to the requirements list.
Ignis has a hard dependency on scikit learn for the measurement
discriminators, but this was never explicitly listed. This was never
caught because the test jobs were always installing it.

* Don't install cvxopt in no-opt job

* Add job name
  • Loading branch information
mtreinish authored Jun 22, 2020
1 parent 01e9070 commit f0b68e4
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 44 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ matrix:
- MPLBACKEND=ps
- PYTHON_VERSION=3.8.1
- TOXENV=py38
- python: "3.8"
name: "Python 3.8 tests without optional dependencies"
stage: all_python
env: TOXENV=no-opt
stage: all_python
script: tox
- if: tag IS present
python: "3.6"
env:
Expand Down
10 changes: 10 additions & 0 deletions releasenotes/notes/missing-dependency-e7c99c7751bcd162.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
upgrade:
- |
A new requirement `scikit-learn <https://scikit-learn.org/stable/>`__ has
been added to the requirements list. This dependency was added in the 0.3.0
release but wasn't properly exposed as a dependency in that release. This
would lead to an ``ImportError`` if the
:mod:`qiskit.ignis.measurement.discriminator.iq_discriminators` module was
imported. This is now correctly listed as a dependency so that
``scikit-learn`` will be installed with qiskit-ignis.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"qiskit-terra>=0.13.0",
"scipy>=0.19,!=0.19.1",
"setuptools>=40.1.0",
"scikit-learn>=0.17",
]


Expand Down
26 changes: 17 additions & 9 deletions test/tomography/test_process_tomography.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,40 @@
from qiskit.quantum_info import Choi

import qiskit.ignis.verification.tomography as tomo
from qiskit.ignis.verification.tomography.fitters import cvx_fit


def run_circuit_and_tomography(circuit, qubits):
def run_circuit_and_tomography(circuit, qubits, method):
choi_ideal = Choi(circuit).data
qst = tomo.process_tomography_circuits(circuit, qubits)
job = qiskit.execute(qst, Aer.get_backend('qasm_simulator'),
shots=5000)
tomo_fit = tomo.ProcessTomographyFitter(job.result(), qst)
choi_cvx = tomo_fit.fit(method='cvx').data
choi_mle = tomo_fit.fit(method='lstsq').data
return (choi_cvx, choi_mle, choi_ideal)
choi = tomo_fit.fit(method=method).data
return (choi, choi_ideal)


class TestProcessTomography(unittest.TestCase):
def setUp(self):
super().setUp()
self.method = 'lstsq'

def test_bell_2_qubits(self):
q2 = QuantumRegister(2)
bell = QuantumCircuit(q2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])

choi_cvx, choi_mle, choi_ideal = run_circuit_and_tomography(bell, q2)
F_bell_cvx = state_fidelity(choi_ideal/4, choi_cvx/4, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(choi_ideal/4, choi_mle/4, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
choi, choi_ideal = run_circuit_and_tomography(bell, q2, self.method)
F_bell = state_fidelity(choi_ideal/4, choi/4, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)


@unittest.skipUnless(cvx_fit._HAS_CVX, 'cvxpy is required for this test')
class TestProcessTomographyCVX(TestProcessTomography):
def setUp(self):
super().setUp()
self.method = 'cvx'


if __name__ == '__main__':
Expand Down
67 changes: 32 additions & 35 deletions test/tomography/test_state_tomography.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,18 @@
import qiskit.ignis.verification.tomography.fitters.cvx_fit as cvx_fit


def run_circuit_and_tomography(circuit, qubits):
def run_circuit_and_tomography(circuit, qubits, method='lstsq'):
psi = Statevector.from_instruction(circuit)
qst = tomo.state_tomography_circuits(circuit, qubits)
job = qiskit.execute(qst, Aer.get_backend('qasm_simulator'),
shots=5000)
tomo_fit = tomo.StateTomographyFitter(job.result(), qst)
rho_cvx = tomo_fit.fit(method='cvx')
rho_mle = tomo_fit.fit(method='lstsq')
return (rho_cvx, rho_mle, psi)
rho = tomo_fit.fit(method=method)
return (rho, psi)


@unittest.skipUnless(cvx_fit._HAS_CVX, 'cvxpy is required to run this test')
class TestFitter(unittest.TestCase):

def test_trace_constraint(self):
p = numpy.array([1/2, 1/2, 1/2, 1/2, 1/2, 1/2])

Expand All @@ -58,29 +57,28 @@ def test_trace_constraint(self):


class TestStateTomography(unittest.TestCase):
def setUp(self):
super().setUp()
self.method = 'lstsq'

def test_bell_2_qubits(self):
q2 = QuantumRegister(2)
bell = QuantumCircuit(q2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])

rho_cvx, rho_mle, psi = run_circuit_and_tomography(bell, q2)
F_bell_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
rho, psi = run_circuit_and_tomography(bell, q2, self.method)
F_bell = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)

def test_bell_2_qubits_no_register(self):
bell = QuantumCircuit(2)
bell.h(0)
bell.cx(0, 1)

rho_cvx, rho_mle, psi = run_circuit_and_tomography(bell, (0, 1))
F_bell_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
rho, psi = run_circuit_and_tomography(bell, (0, 1), self.method)
F_bell = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)

def test_different_qubit_sets(self):
circuit = QuantumCircuit(5)
Expand All @@ -92,12 +90,10 @@ def test_different_qubit_sets(self):
circuit.cx(1, 3)

for qubit_pair in [(0, 1), (2, 3), (1, 4), (0, 3)]:
rho_cvx, rho_mle, psi = run_circuit_and_tomography(circuit, qubit_pair)
rho, psi = run_circuit_and_tomography(circuit, qubit_pair, self.method)
psi = partial_trace(psi, [x for x in range(5) if x not in qubit_pair])
F_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_cvx, 1, places=1)
F_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_mle, 1, places=1)
F = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F, 1, places=1)

def test_bell_3_qubits(self):
q3 = QuantumRegister(3)
Expand All @@ -106,22 +102,18 @@ def test_bell_3_qubits(self):
bell.cx(q3[0], q3[1])
bell.cx(q3[1], q3[2])

rho_cvx, rho_mle, psi = run_circuit_and_tomography(bell, q3)
F_bell_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
rho, psi = run_circuit_and_tomography(bell, q3, self.method)
F_bell = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)

def test_complex_1_qubit_circuit(self):
q = QuantumRegister(1)
circ = QuantumCircuit(q)
circ.u3(1, 1, 1, q[0])

rho_cvx, rho_mle, psi = run_circuit_and_tomography(circ, q)
F_bell_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
rho, psi = run_circuit_and_tomography(circ, q, self.method)
F_bell = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)

def test_complex_3_qubit_circuit(self):
def rand_angles():
Expand All @@ -133,11 +125,16 @@ def rand_angles():
for j in range(3):
circ.u3(*rand_angles(), q[j])

rho_cvx, rho_mle, psi = run_circuit_and_tomography(circ, q)
F_bell_cvx = state_fidelity(psi, rho_cvx, validate=False)
self.assertAlmostEqual(F_bell_cvx, 1, places=1)
F_bell_mle = state_fidelity(psi, rho_mle, validate=False)
self.assertAlmostEqual(F_bell_mle, 1, places=1)
rho, psi = run_circuit_and_tomography(circ, q, self.method)
F_bell = state_fidelity(psi, rho, validate=False)
self.assertAlmostEqual(F_bell, 1, places=1)


@unittest.skipUnless(cvx_fit._HAS_CVX, 'cvxpy is required to run this test')
class TestStateTomographyCVX(TestStateTomography):
def setUp(self):
super().setUp()
self.method = 'cvx'


if __name__ == '__main__':
Expand Down
10 changes: 10 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ commands =
pip check
stestr run {posargs}

[testenv:no-opt]
deps =
git+https://github.com/Qiskit/qiskit-terra.git
qiskit-aer
ddt>=1.2.0,!=1.4.0
stestr>=2.5.0
commands =
pip check
stestr run {posargs}

[testenv:lint]
basepython = python3
deps =
Expand Down

0 comments on commit f0b68e4

Please sign in to comment.