generated from gecrooks/modern-python-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port diamond norm from quantumflow to own package
- Loading branch information
Showing
11 changed files
with
253 additions
and
733 deletions.
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
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
3 changes: 2 additions & 1 deletion
3
gecrooks_python_template/__init__.py → qf_diamond_norm/__init__.py
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 |
---|---|---|
@@ -1,7 +1,8 @@ | ||
# Copyright 2019-2021, Gavin E. Crooks and contributors | ||
# | ||
# This source code is licensed under the Apache License, Version 2.0 found in | ||
# This source code is licensed under the Apache License 2.0 found in | ||
# the LICENSE.txt file in the root directory of this source tree. | ||
|
||
from .config import __version__ # noqa: F401 | ||
from .config import about # noqa: F401 | ||
from .info import diamond_norm # noqa: F401 |
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 |
---|---|---|
@@ -1,15 +1,15 @@ | ||
# Copyright 2019-2021, Gavin E. Crooks and contributors | ||
# | ||
# This source code is licensed under the Apache License, Version 2.0 found in | ||
# This source code is licensed under the Apache License 2.0 found in | ||
# the LICENSE.txt file in the root directory of this source tree. | ||
|
||
# Command line interface for the about() function | ||
# > python -m gecrooks_python_template.about | ||
# > python -m qf_diamond_norm.about | ||
# | ||
# NB: This module should not be imported by any other code in the package | ||
# (else we will get multiple import warnings) | ||
|
||
if __name__ == "__main__": | ||
import gecrooks_python_template | ||
import qf_diamond_norm | ||
|
||
gecrooks_python_template.about() | ||
qf_diamond_norm.about() |
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
14 changes: 7 additions & 7 deletions
14
gecrooks_python_template/config_test.py → qf_diamond_norm/config_test.py
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,83 @@ | ||
# Copyright 2020-, Gavin E. Crooks and contributors | ||
# | ||
# This source code is licensed under the Apache License 2.0 found in | ||
# the LICENSE.txt file in the root directory of this source tree. | ||
|
||
|
||
""" | ||
==================== | ||
Information Measures | ||
==================== | ||
Channel Measures | ||
################# | ||
.. autofunction:: diamond_norm | ||
""" | ||
|
||
import numpy as np | ||
from quantumflow import Channel | ||
|
||
__all__ = ("diamond_norm",) | ||
|
||
|
||
def diamond_norm(chan0: Channel, chan1: Channel) -> float: | ||
"""Return the diamond norm between two completely positive | ||
trace-preserving (CPTP) superoperators. | ||
Note: Requires "cvxpy" package (and dependencies) to be fully installed. | ||
The calculation uses the simplified semidefinite program of Watrous | ||
[arXiv:0901.4709](http://arxiv.org/abs/0901.4709) | ||
[J. Watrous, [Theory of Computing 5, 11, pp. 217-238 | ||
(2009)](http://theoryofcomputing.org/articles/v005a011/)] | ||
""" | ||
# Kudos: Based on MatLab code written by Marcus P. da Silva | ||
# (https://github.com/BBN-Q/matlab-diamond-norm/) | ||
import cvxpy as cvx | ||
|
||
if set(chan0.qubits) != set(chan1.qubits): | ||
raise ValueError("Channels must operate on same qubits") | ||
|
||
if chan0.qubits != chan1.qubits: | ||
chan1 = chan1.permute(chan0.qubits) | ||
|
||
N = chan0.qubit_nb | ||
dim = 2 ** N | ||
|
||
choi0 = chan0.choi() | ||
choi1 = chan1.choi() | ||
|
||
delta_choi = choi0 - choi1 | ||
|
||
# Density matrix must be Hermitian, positive semidefinite, trace 1 | ||
rho = cvx.Variable([dim, dim], complex=True) | ||
constraints = [rho == rho.H] | ||
constraints += [rho >> 0] | ||
constraints += [cvx.trace(rho) == 1] | ||
|
||
# W must be Hermitian, positive semidefinite | ||
W = cvx.Variable([dim ** 2, dim ** 2], complex=True) | ||
constraints += [W == W.H] | ||
constraints += [W >> 0] | ||
|
||
constraints += [(W - cvx.kron(np.eye(dim), rho)) << 0] | ||
|
||
J = cvx.Parameter([dim ** 2, dim ** 2], complex=True) | ||
objective = cvx.Maximize(cvx.real(cvx.trace(J.H * W))) | ||
|
||
prob = cvx.Problem(objective, constraints) | ||
|
||
J.value = delta_choi | ||
prob.solve() | ||
|
||
dnorm = prob.value * 2 | ||
|
||
# Diamond norm is between 0 and 2. Correct for floating point errors | ||
dnorm = min(2, dnorm) | ||
dnorm = max(0, dnorm) | ||
|
||
return dnorm | ||
|
||
|
||
# fin |
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,76 @@ | ||
# Copyright 2020-, Gavin E. Crooks and contributors | ||
# | ||
# This source code is licensed under the Apache License 2.0 found in | ||
# the LICENSE.txt file in the root directory of this source tree. | ||
|
||
import numpy as np | ||
import pytest | ||
import quantumflow as qf | ||
|
||
from qf_diamond_norm import diamond_norm | ||
|
||
|
||
def test_diamond_norm() -> None: | ||
# Test cases borrowed from qutip, | ||
# https://github.com/qutip/qutip/blob/master/qutip/tests/test_metrics.py | ||
# which were in turn generated using QuantumUtils for MATLAB | ||
# (https://goo.gl/oWXhO9) | ||
|
||
RTOL = 0.01 | ||
chan0 = qf.I(0).aschannel() | ||
chan1 = qf.X(0).aschannel() | ||
dn = diamond_norm(chan0, chan1) | ||
assert np.isclose(2.0, dn, rtol=RTOL) | ||
|
||
turns_dnorm = [ | ||
[1.000000e-03, 3.141591e-03], | ||
[3.100000e-03, 9.738899e-03], | ||
[1.000000e-02, 3.141463e-02], | ||
[3.100000e-02, 9.735089e-02], | ||
[1.000000e-01, 3.128689e-01], | ||
[3.100000e-01, 9.358596e-01], | ||
] | ||
|
||
for turns, target in turns_dnorm: | ||
chan0 = qf.XPow(0.0, 0).aschannel() | ||
chan1 = qf.XPow(turns, 0).aschannel() | ||
|
||
dn = diamond_norm(chan0, chan1) | ||
assert np.isclose(target, dn, rtol=RTOL) | ||
|
||
hadamard_mixtures = [ | ||
[1.000000e-03, 2.000000e-03], | ||
[3.100000e-03, 6.200000e-03], | ||
[1.000000e-02, 2.000000e-02], | ||
[3.100000e-02, 6.200000e-02], | ||
[1.000000e-01, 2.000000e-01], | ||
[3.100000e-01, 6.200000e-01], | ||
] | ||
|
||
for p, target in hadamard_mixtures: | ||
tensor = qf.I(0).aschannel().tensor * (1 - p) + qf.H(0).aschannel().tensor * p | ||
chan0 = qf.Channel(tensor, [0]) | ||
|
||
chan1 = qf.I(0).aschannel() | ||
|
||
dn = diamond_norm(chan0, chan1) | ||
assert np.isclose(dn, target, rtol=RTOL) | ||
|
||
chan0 = qf.YPow(0.5, 0).aschannel() | ||
chan1 = qf.I(0).aschannel() | ||
dn = diamond_norm(chan0, chan1) | ||
assert np.isclose(dn, np.sqrt(2), rtol=RTOL) | ||
|
||
chan0 = qf.CNot(0, 1).aschannel() | ||
chan1 = qf.CNot(1, 0).aschannel() | ||
diamond_norm(chan0, chan1) | ||
|
||
|
||
def test_diamond_norm_err() -> None: | ||
with pytest.raises(ValueError): | ||
chan0 = qf.I(0).aschannel() | ||
chan1 = qf.I(1).aschannel() | ||
diamond_norm(chan0, chan1) | ||
|
||
|
||
# fin |
Oops, something went wrong.