Skip to content

Commit

Permalink
Merge pull request #110 from BoxiLi/qutip-qip-0.1.X
Browse files Browse the repository at this point in the history
Prepare the qutip-qip-0.1.2 release
  • Loading branch information
BoxiLi committed Nov 24, 2021
2 parents 10497b5 + bf02c91 commit 25883cc
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 63 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.1
0.1.2
57 changes: 57 additions & 0 deletions doc/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
.. _changelog:

**********
Change Log
**********

Version 0.1.2 (Nov 25, 2021)
++++++++++++++++++++++++++++
This micro release adds more thorough documentation for the project and fixes a few bugs in :obj:`.QubitCircuit` and :obj:`.Processor`.

PRs are collected at `https://github.com/qutip/qutip-qip/milestone/4?closed=1 <https://github.com/qutip/qutip-qip/milestone/4?closed=1>`_.

Improvements
------------
- Efficient Hadamard transform. (`#103 <https://github.com/qutip/qutip-qip/pull/103>`_)
- Make circuit latex code accessible in `QubitCircuit`. (`#108 <https://github.com/qutip/qutip-qip/pull/108>`_)


Bug Fixes
----------
- Fix the leaking noise objects in `Processor`. (`#89 <https://github.com/qutip/qutip-qip/pull/89>`_)
- Fix a bug in time-dependent collapse operators in `Processor`. (`#107 <https://github.com/qutip/qutip-qip/pull/107>`_)


Version 0.1.1 (July 28, 2021)
+++++++++++++++++++++++++++++

This micro release adds more thorough documentation for the project and fixes a few bugs in :obj:`.QubitCircuit` and :obj:`.Processor`.

PRs are collected `here <https://github.com/qutip/qutip-qip/milestone/2?closed=1>`_.

Improvements
------------
- Improve the documentation.
- Workflows for releases and automatically building the documentation, migrated from ``qutip``. (`#49 <https://github.com/qutip/qutip-qip/pull/49>`_, `#78 <https://github.com/qutip/qutip-qip/pull/78>`_)
- The part of tex code taken from circuit is removed due to licence issue. Instead, the latex code now requires the user to install `qcircuit` in advance. (`#61 <https://github.com/qutip/qutip-qip/pull/61>`_)
- Rename :obj:`.Noise.get_noisy_dynamics` with :obj:`.Noise.get_noisy_pulses`. The new name is more appropriate because it returns a list of :obj:`.Pulse`, not a ``QobjEvo``. The old API is deprecated. (`#76 <https://github.com/qutip/qutip-qip/pull/76>`_)
- Add more thorough documentation for installing external dependencies for circuit plotting. (`#65 <https://github.com/qutip/qutip-qip/pull/65>`_)

Bug Fixes
---------
- Add the missing drift Hamiltonian to the method :obj:`.Processor.run_analytically`. It was missing because only the control part of the Hamiltonian is added. (`#74 <https://github.com/qutip/qutip-qip/pull/74>`_)
- Fix a few bugs in :obj:`.QubitCircuit`: Make `QubitCircuit.propagators_no_expand` private. It will be removed and replaced by :obj:`.QubitCircuit.propagators`. The attributes :obj:`.QubitCircuit.U_list` is also removed. (`#66 <https://github.com/qutip/qutip-qip/pull/66>`_)

Developer Changes
-----------------
- Documentation is moved from ``/docs`` to ``/doc``. (`#49 <https://github.com/qutip/qutip-qip/pull/49>`_, `#78 <https://github.com/qutip/qutip-qip/pull/78>`_)


Version 0.1.0 (May 14, 2021)
++++++++++++++++++++++++++++

This is the first release of qutip-qip, the Quantum Information Processing package in QuTiP.

The qutip-qip package used to be a module ``qutip.qip`` under `QuTiP (Quantum Toolbox in Python) <http://qutip.org/index.html>`_. From QuTiP 5.0, the community has decided to decrease the size of the core QuTiP package by reducing the external dependencies, in order to simplify maintenance. Hence a few modules are separated from the core QuTiP and will become QuTiP family packages. They are still maintained by the QuTiP team but hosted under different repositories in the `QuTiP organization <https://github.com/qutip>`_.

The qutip-qip package, QuTiP quantum information processing, aims at providing basic tools for quantum computing simulation both for simple quantum algorithm design and for experimental realization. Compared to other libraries for quantum information processing, qutip-qip puts additional emphasis on the physics layer and the interaction with the QuTiP package. The package offers two different approaches for simulating quantum circuits, one with :obj:`.QubitCircuit` calculating unitary evolution under quantum gates by matrix product, another called :obj:`.Processor` using open system solvers in QuTiP to simulate the execution of quantum circuits on a noisy quantum device.
6 changes: 6 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ qutip-qip: QuTiP quantum information processing
contribution-code.rst
contribution-docs.rst

.. toctree::
:maxdepth: 2
:caption: Changelog

changelog.rst

.. toctree::
:maxdepth: 2
:caption: API documentation
Expand Down
76 changes: 38 additions & 38 deletions doc/source/qip-simulator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ method.

.. testcode::

from qutip import tensor
from qutip import tensor, basis
zero_state = tensor(basis(2, 0), basis(2, 0), basis(2, 0))
result = qc.run(state=zero_state)
wstate = result
Expand Down Expand Up @@ -93,42 +93,42 @@ outputs, we can use the :meth:`.QubitCircuit.run_statistics` function:
.. testoutput::
:options: +NORMALIZE_WHITESPACE

State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]
[0.]
[0.]
[0.]]
with probability 0.33333257054168813
State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[0.]
[1.]
[0.]
[0.]
[0.]
[0.]
[0.]]
with probability 0.33333257054168813
State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[0.]
[1.]
[0.]
[0.]
[0.]]
with probability 0.33333485891662384
State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]
[0.]
[0.]
[0.]]
with probability 0.3333325705416881
State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[0.]
[1.]
[0.]
[0.]
[0.]
[0.]
[0.]]
with probability 0.3333325705416881
State:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[0.]
[1.]
[0.]
[0.]
[0.]]
with probability 0.33333485891662384

The function returns a :class:`~.Result` object which contains
the output states.
Expand Down Expand Up @@ -186,7 +186,7 @@ The :class:`.CircuitSimulator` class also enables stepping through the circuit:
[0. ]
[0. ]]

This only excutes one gate in the circuit and
This only executes one gate in the circuit and
allows for a better understanding of how the state evolution takes place.
The method steps through both the gates and the measurements.

Expand Down
15 changes: 14 additions & 1 deletion src/qutip_qip/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ class QubitCircuit:
A list of integer for the dimension of each composite system.
e.g [2,2,2,2,2] for 5 qubits system. If None, qubits system
will be the default option.
num_cbits : int
Number of classical bits in the system.
Examples
--------
Expand Down Expand Up @@ -1805,7 +1807,7 @@ def latex_code(self):
code += r" & %s" % rows[m][n]
code += r" & \qw \\ " + "\n"

return code
return _latex_template % code

# This slightly convoluted dance with the conversion formats is because
# image conversion has optional dependencies. We always want the `png` and
Expand Down Expand Up @@ -1866,6 +1868,17 @@ def _to_qasm(self, qasm_out):
op._to_qasm(qasm_out)


_latex_template = r"""
\documentclass{standalone}
\usepackage[braket]{qcircuit}
\renewcommand{\qswap}{*=<0em>{\times}}
\begin{document}
\Qcircuit @C=1cm @R=1cm {
%s}
\end{document}
"""


class CircuitResult:

def __init__(self, final_states, probabilities, cbits=None):
Expand Down
17 changes: 6 additions & 11 deletions src/qutip_qip/circuit_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,6 @@
import tempfile
import warnings

_latex_template = r"""
\documentclass{standalone}
\usepackage[braket]{qcircuit}
\renewcommand{\qswap}{*=<0em>{\times}}
\begin{document}
\Qcircuit @C=1cm @R=1cm {
%s}
\end{document}
"""


def _run_command(command, *args, **kwargs):
"""
Expand Down Expand Up @@ -228,7 +218,7 @@ def image_from_latex(code, file_type="png"):
try:
os.chdir(temporary_dir)
with open(filename + ".tex", "w") as file:
file.write(_latex_template % code)
file.write(code)
try:
_run_command((_pdflatex, '-interaction', 'batchmode',
filename))
Expand All @@ -238,6 +228,11 @@ def image_from_latex(code, file_type="png"):
" Perhaps you do not have it installed, or you are"
" missing the LaTeX package 'qcircuit'."
)
message += (
"The latex code is printed below. "
"Please try to compile locally using pdflatex:\n"
+ code
)
raise RuntimeError(message) from e
_crop_pdf(filename + ".pdf")
if file_type in _MISSING_CONVERTERS:
Expand Down
3 changes: 1 addition & 2 deletions src/qutip_qip/device/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,10 +669,9 @@ def get_qobjevo(self, args=None, noisy=False):
final_qu.args.update(args)

# bring all c_ops to the same tlist, won't need it in QuTiP 5
full_tlist = self.get_full_tlist()
temp = []
for c_op in c_ops:
temp.append(_merge_qobjevo([c_op], full_tlist))
temp.append(_merge_qobjevo([c_op], final_qu.tlist))
c_ops = temp

if noisy:
Expand Down
1 change: 1 addition & 0 deletions src/qutip_qip/noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def process_noise(pulses, noise_list, dims, t1=None, t2=None,
noisy_pulses: list of :class:`.Pulse`
The noisy pulses, including the system noise.
"""
noise_list = noise_list.copy()
noisy_pulses = deepcopy(pulses)
systematic_noise = Pulse(None, None, label="systematic_noise")

Expand Down
7 changes: 3 additions & 4 deletions src/qutip_qip/operations/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,11 +924,10 @@ def hadamard_transform(N=1):
Quantum object representation of the N-qubit Hadamard gate.
"""
data = 2 ** (-N / 2) * np.array([[(-1) ** _hamming_distance(i & j)
for i in range(2 ** N)]
for j in range(2 ** N)])
data = [[1, 1], [1, -1]]
H = Qobj(data) / np.sqrt(2)

return Qobj(data, dims=[[2] * N, [2] * N])
return tensor([H] * N)


def _flatten(lst):
Expand Down
12 changes: 11 additions & 1 deletion tests/test_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,20 @@ def test_wstate(self):
np.testing.assert_allclose(probs_initial, probs_final)
assert sum(result_cbits[i]) == 1

_latex_template = r"""
\documentclass{standalone}
\usepackage[braket]{qcircuit}
\renewcommand{\qswap}{*=<0em>{\times}}
\begin{document}
\Qcircuit @C=1cm @R=1cm {
%s}
\end{document}
"""

def test_latex_code_teleportation_circuit(self):
qc = _teleportation_circuit()
latex = qc.latex_code()
assert latex == "\n".join([
assert latex == self._latex_template % "\n".join([
r" & \lstick{c1} & \qw & \qw & \qw & \qw"
r" & \qw \cwx[4] & \qw & \qw & \ctrl{2} & \qw \\ ",
r" & \lstick{c0} & \qw & \qw & \qw & \qw"
Expand Down
17 changes: 17 additions & 0 deletions tests/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,23 @@ def test_cnot_explicit(self):
[0, 0, 0, 1, 0, 0, 0, 0]])
np.testing.assert_allclose(test, expected, atol=1e-15)

def test_hadamard_explicit(self):
test = gates.hadamard_transform(3).full()
expected = np.array(
[
[1, 1, 1, 1, 1, 1, 1, 1],
[1, -1, 1, -1, 1, -1, 1, -1],
[1, 1, -1, -1, 1, 1, -1, -1],
[1, -1, -1, 1, 1, -1, -1, 1],
[1, 1, 1, 1, -1, -1, -1, -1],
[1, -1, 1, -1, -1, 1, -1, 1],
[1, 1, -1, -1, -1, -1, 1, 1],
[1, -1, -1, 1, -1, 1, 1, -1],
]
)
expected = expected / np.sqrt(8)
np.testing.assert_allclose(test, expected)

def test_cyclic_permutation(self):
operators = [qutip.sigmax(), qutip.sigmaz()]
test = gates.expand_operator(qutip.tensor(*operators), N=3,
Expand Down
20 changes: 18 additions & 2 deletions tests/test_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

from qutip import (
tensor, qeye, sigmaz, sigmax, sigmay, destroy, identity, QobjEvo,
fidelity, basis
fidelity, basis, sigmam
)
from qutip_qip.device import Processor, SCQubits
from qutip_qip.device import Processor, SCQubits, LinearSpinChain
from qutip_qip.noise import (
RelaxationNoise, DecoherenceNoise, ControlAmpNoise, RandomNoise,
ZZCrossTalk, Noise)
Expand Down Expand Up @@ -50,6 +50,22 @@ def test_decoherence_noise(self):
assert_allclose(c_ops[0].tlist, tlist)
assert_allclose(c_ops[1].ops[0].qobj, tensor(qeye(2), sigmax()))

def test_collapse_with_different_tlist(self):
"""
Test if there are errors raised because of wrong tlist handling.
"""
qc = QubitCircuit(1)
qc.add_gate("X", 0)
proc = LinearSpinChain(1)
proc.load_circuit(qc)
tlist = np.linspace(0, 30., 100)
coeff = tlist * 0.1
noise = DecoherenceNoise(
sigmam(), targets=0,
coeff=coeff, tlist=tlist)
proc.add_noise(noise)
proc.run_state(basis(2, 0))

def test_relaxation_noise(self):
"""
Test for the relaxation noise
Expand Down
19 changes: 16 additions & 3 deletions tests/test_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ def testPlot(self):
processor.add_control(sigmaz())
processor.pulses[0].tlist = tlist
processor.pulses[0].coeff = np.array([np.sin(t) for t in tlist])
processor.plot_pulses()
plt.clf()
fig, _ = processor.plot_pulses()
# testing under Xvfb with pytest-xvfb complains if figure windows are
# left open, so we politely close it:
plt.close(fig)

# cubic spline
tlist = np.linspace(0., 2*np.pi, 20)
Expand All @@ -184,7 +186,10 @@ def testPlot(self):
processor.pulses[0].tlist = tlist
processor.pulses[0].coeff = np.array([np.sin(t) for t in tlist])
processor.plot_pulses()
plt.clf()
fig, _ = processor.plot_pulses()
# testing under Xvfb with pytest-xvfb complains if figure windows are
# left open, so we politely close it:
plt.close(fig)

def testSpline(self):
"""
Expand Down Expand Up @@ -365,3 +370,11 @@ def test_pulse_dict(self):
processor = Processor(1)
processor.add_control(sigmax(), 0, label="test")
assert("test" in processor.get_pulse_dict())

def test_repeated_use_of_processor(self):
processor = Processor(1, t1=1.)
processor.add_pulse(
Pulse(sigmax(), targets=0, coeff=True))
result1 = processor.run_state(basis(2, 0), tlist=np.linspace(0, 1, 10))
result2 = processor.run_state(basis(2, 0), tlist=np.linspace(0, 1, 10))
assert_allclose(result1.states[-1].full(), result2.states[-1].full())

0 comments on commit 25883cc

Please sign in to comment.