iqm-benchmarks 2.44__py3-none-any.whl → 2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iqm/benchmarks/benchmark_definition.py +1 -0
- iqm/benchmarks/compressive_gst/compressive_gst.py +100 -46
- iqm/benchmarks/compressive_gst/gst_analysis.py +480 -381
- iqm/benchmarks/entanglement/ghz.py +2 -2
- iqm/benchmarks/optimization/qscore.py +2 -2
- {iqm_benchmarks-2.44.dist-info → iqm_benchmarks-2.45.dist-info}/METADATA +2 -2
- {iqm_benchmarks-2.44.dist-info → iqm_benchmarks-2.45.dist-info}/RECORD +17 -17
- mGST/additional_fns.py +35 -20
- mGST/algorithm.py +73 -57
- mGST/low_level_jit.py +122 -56
- mGST/optimization.py +12 -6
- mGST/qiskit_interface.py +64 -87
- mGST/reporting/figure_gen.py +390 -57
- mGST/reporting/reporting.py +209 -11
- {iqm_benchmarks-2.44.dist-info → iqm_benchmarks-2.45.dist-info}/WHEEL +0 -0
- {iqm_benchmarks-2.44.dist-info → iqm_benchmarks-2.45.dist-info}/licenses/LICENSE +0 -0
- {iqm_benchmarks-2.44.dist-info → iqm_benchmarks-2.45.dist-info}/top_level.txt +0 -0
|
@@ -96,7 +96,7 @@ def fidelity_ghz_randomized_measurements(
|
|
|
96
96
|
p_sum = []
|
|
97
97
|
for sb in c_id_keys:
|
|
98
98
|
for sa in c_keys:
|
|
99
|
-
exponent = hamming(list(sa), list(sb)) * num_qubits
|
|
99
|
+
exponent = hamming(np.array(list(sa)), np.array(list(sb))) * num_qubits
|
|
100
100
|
p_sum.append(np.power(-2, -exponent) * probabilities_sample[sa] * ideal_probabilities[u][sb])
|
|
101
101
|
fid_rm.append((2**num_qubits) * sum(p_sum))
|
|
102
102
|
values = {"fidelity": np.mean(fid_rm)}
|
|
@@ -117,7 +117,7 @@ def fidelity_ghz_randomized_measurements(
|
|
|
117
117
|
p_sum = []
|
|
118
118
|
for sb in c_id_keys:
|
|
119
119
|
for sa in c_keys:
|
|
120
|
-
exponent = hamming(list(sa), list(sb)) * num_qubits
|
|
120
|
+
exponent = hamming(np.array(list(sa)), np.array(list(sb))) * num_qubits
|
|
121
121
|
p_sum.append(np.power(-2, -exponent) * probabilities_sample[sa] * ideal_probabilities[u][sb])
|
|
122
122
|
fid_rm_rem.append((2**num_qubits) * sum(p_sum))
|
|
123
123
|
values = values | {"fidelity_rem": np.mean(fid_rm_rem)}
|
|
@@ -83,9 +83,9 @@ def calculate_optimal_angles_for_QAOA_p1(graph: Graph) -> List[float]:
|
|
|
83
83
|
x_init = [0.15, -0.28]
|
|
84
84
|
|
|
85
85
|
minimizer_kwargs = {"method": "L-BFGS-B", "bounds": bounds}
|
|
86
|
-
res = basinhopping(get_expected_zz_edgedensity, x_init, minimizer_kwargs=minimizer_kwargs, niter=10, T=2)
|
|
86
|
+
res = basinhopping(get_expected_zz_edgedensity, x_init, minimizer_kwargs=minimizer_kwargs, niter=10, T=2) # type: ignore
|
|
87
87
|
|
|
88
|
-
return res.x
|
|
88
|
+
return list(res.x)
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def cut_cost_function(x: str, graph: Graph) -> int:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iqm-benchmarks
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.45
|
|
4
4
|
Summary: A package for implementation of Quantum Characterization, Verification and Validation (QCVV) techniques on IQM's hardware at gate level abstraction
|
|
5
5
|
Author-email: IQM Finland Oy <developers@meetiqm.com>, Adrian Auer <adrian.auer@meetiqm.com>, Raphael Brieger <raphael.brieger@meetiqm.com>, Alessio Calzona <alessio.calzona@meetiqm.com>, Pedro Figueroa Romero <pedro.romero@meetiqm.com>, Amin Hosseinkhani <amin.hosseinkhani@meetiqm.com>, Miikka Koistinen <miikka@meetiqm.com>, Nadia Milazzo <nadia.milazzo@meetiqm.com>, Vicente Pina Canelles <vicente.pina@meetiqm.com>, Aniket Rath <aniket.rath@meetiqm.com>, Jami Rönkkö <jami@meetiqm.com>, Stefan Seegerer <stefan.seegerer@meetiqm.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/iqm-finland/iqm-benchmarks
|
|
@@ -63,7 +63,7 @@ Below is a list of the benchmarks currently available in the suite:
|
|
|
63
63
|
* Gates / Layers:
|
|
64
64
|
- Standard Clifford Randomized Benchmarking [[Phys. Rev. A 85, 042311](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.85.042311) (2012)]
|
|
65
65
|
- Interleaved Randomized Benchmarking [[Phys. Rev. Lett. 109, 080505](https://doi.org/10.1103/PhysRevLett.109.080505) (2012)]
|
|
66
|
-
- Compressive Gate Set Tomography [[PRX Quantum 4, 010325](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.4.010325) (2023)]
|
|
66
|
+
- Compressive Gate Set Tomography [[PRX Quantum 4, 010325](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.4.010325) (2023)] (Optional dependencies required)
|
|
67
67
|
- Mirror Randomized Benchmarking [[Phys. Rev. Lett. 129, 150502](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.129.150502) (2022)]
|
|
68
68
|
- Error Per Layered Gate [[arXiv:2311.05933 [quant-ph]](https://arxiv.org/abs/2311.05933) (2023)]
|
|
69
69
|
* Holistic:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
iqm/benchmarks/__init__.py,sha256=-drZ_whue067Tu4I9RxBCqrrzu38Tm5Kqf9jHTftUPk,3070
|
|
2
2
|
iqm/benchmarks/benchmark.py,sha256=3E7g7RQjCIGIpSI1gOSrI3V9SAVs-XEOMrPgToK_7vw,4972
|
|
3
|
-
iqm/benchmarks/benchmark_definition.py,sha256=
|
|
3
|
+
iqm/benchmarks/benchmark_definition.py,sha256=7sq9_Y0iu1ZJOjG0gAVpm_BK3hbJBa6bdcRKhcVFOJw,11321
|
|
4
4
|
iqm/benchmarks/circuit_containers.py,sha256=anEtZEsodYqOX-34oZRmuKGeEpp_VfgG5045Mz4-4hI,7562
|
|
5
5
|
iqm/benchmarks/logging_config.py,sha256=U7olP5Kr75AcLJqNODf9VBhJLVqIvA4AYR6J39D5rww,1052
|
|
6
6
|
iqm/benchmarks/readout_mitigation.py,sha256=Q2SOGWTNgmklOYkNxepAaSaXlxSj0QQyymYY1bOkT8A,11756
|
|
@@ -10,13 +10,13 @@ iqm/benchmarks/utils_shadows.py,sha256=e77PV_uaAO5m_woox9lAzompKAvFeDJ-0AKJrNJ7N
|
|
|
10
10
|
iqm/benchmarks/coherence/__init__.py,sha256=yeyhk-_Lp8IbJ-f5lQj0HP5Q1HSKK_FzuXHazotUrVY,704
|
|
11
11
|
iqm/benchmarks/coherence/coherence.py,sha256=zX_6A8vCS2zeWesMDXPFZBfrJ8wUG90JI9_tFsonwXk,21191
|
|
12
12
|
iqm/benchmarks/compressive_gst/__init__.py,sha256=LneifgYXtcwo2jcXo7GdUEHL6_peipukShhkrdaTRCA,929
|
|
13
|
-
iqm/benchmarks/compressive_gst/compressive_gst.py,sha256=
|
|
14
|
-
iqm/benchmarks/compressive_gst/gst_analysis.py,sha256=
|
|
13
|
+
iqm/benchmarks/compressive_gst/compressive_gst.py,sha256=c33PUisGlmPUkt4Nx2Xqmduji5qFCrWT9jMcoThcs7U,27992
|
|
14
|
+
iqm/benchmarks/compressive_gst/gst_analysis.py,sha256=H6EQGbpI_sig69Jy6hflg6alMTtjB0t9tHftygzA2YA,41240
|
|
15
15
|
iqm/benchmarks/entanglement/__init__.py,sha256=sHVVToRWRCz0LSntk1rQaoSNNeyZLPoiTjUKWZWrk1E,778
|
|
16
|
-
iqm/benchmarks/entanglement/ghz.py,sha256=
|
|
16
|
+
iqm/benchmarks/entanglement/ghz.py,sha256=7QI7r9x5VEYQu5kqmdsLV9nq3eedYV_WRVqCQTbjapk,41294
|
|
17
17
|
iqm/benchmarks/entanglement/graph_states.py,sha256=saoAw2QF8j7W4nZMOElnjuNylqDAbY9cBwBypWZKUz8,62521
|
|
18
18
|
iqm/benchmarks/optimization/__init__.py,sha256=_ajW_OibYLCtzU5AUv5c2zuuVYn8ZNeZUcUUSIGt51M,747
|
|
19
|
-
iqm/benchmarks/optimization/qscore.py,sha256=
|
|
19
|
+
iqm/benchmarks/optimization/qscore.py,sha256=hh96ZVYU7rUYCBEQyhFZNv0IOQoAwM5RYfRvqRl05ow,37281
|
|
20
20
|
iqm/benchmarks/quantum_volume/__init__.py,sha256=i-Q4SpDWELBw7frXnxm1j4wJRcxbIyrS5uEK_v06YHo,951
|
|
21
21
|
iqm/benchmarks/quantum_volume/clops.py,sha256=QS9iK-gtop0zix6IBeUumQeG01-0dXsv0jsYSDhgEu0,31071
|
|
22
22
|
iqm/benchmarks/quantum_volume/quantum_volume.py,sha256=pro7Lz-A5pPpT9UZ8wtXKTyhdWmTjQjRHt4BylDR-3U,36553
|
|
@@ -35,18 +35,18 @@ iqm/benchmarks/randomized_benchmarking/interleaved_rb/__init__.py,sha256=sq6MgN_
|
|
|
35
35
|
iqm/benchmarks/randomized_benchmarking/interleaved_rb/interleaved_rb.py,sha256=TaR1YFWBhOgm1hmEQzuwLYpp0yl0Xpuo3jAT6YhiXpc,28471
|
|
36
36
|
iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py,sha256=jRKbivWCZ3xdO1k0sx-ygC3s5DUkGSModd975PoAtcg,692
|
|
37
37
|
iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py,sha256=n_5gt9636ZDMsM9hC3Zm5qP2bQr2sy41zxGhOh0XMjI,32932
|
|
38
|
-
iqm_benchmarks-2.
|
|
38
|
+
iqm_benchmarks-2.45.dist-info/licenses/LICENSE,sha256=2Ncb40-hqkTil78RPv3-YiJfKaJ8te9USJgliKqIdSY,11558
|
|
39
39
|
mGST/LICENSE,sha256=TtHNq55cUcbglb7uhVudeBLUh_qPdUoAEvU0BBwFz-k,1098
|
|
40
40
|
mGST/README.md,sha256=v_5kw253csHF4-RfE-44KqFmBXIsSMRmOtN0AUPrRxE,5050
|
|
41
|
-
mGST/additional_fns.py,sha256=
|
|
42
|
-
mGST/algorithm.py,sha256=
|
|
41
|
+
mGST/additional_fns.py,sha256=MV0Pm5ap59IjhT_E3QhsZyM7lXOF1RZ9SD11zoaf43A,31781
|
|
42
|
+
mGST/algorithm.py,sha256=2xeIiPP1ae8IgBgrc7boTk-NyirUMJimcZTvKMbZqKY,27504
|
|
43
43
|
mGST/compatibility.py,sha256=00DsPnNfOtrQcDTvxBDs-0aMhmuXmOIIxl_Ohy-Emkg,8920
|
|
44
|
-
mGST/low_level_jit.py,sha256=
|
|
45
|
-
mGST/optimization.py,sha256=
|
|
46
|
-
mGST/qiskit_interface.py,sha256=
|
|
47
|
-
mGST/reporting/figure_gen.py,sha256=
|
|
48
|
-
mGST/reporting/reporting.py,sha256=
|
|
49
|
-
iqm_benchmarks-2.
|
|
50
|
-
iqm_benchmarks-2.
|
|
51
|
-
iqm_benchmarks-2.
|
|
52
|
-
iqm_benchmarks-2.
|
|
44
|
+
mGST/low_level_jit.py,sha256=Ih1MxcwU0GnSRu0TI9GaYxpB94CMuJ8Is1eTeOwsfA8,30772
|
|
45
|
+
mGST/optimization.py,sha256=x9tJ9wMQ5aONWpNpBMVtK0rwE6DRcOU33htNgrt0tx4,11015
|
|
46
|
+
mGST/qiskit_interface.py,sha256=uCdn-Q9CXI2f4FQSxGUy8GmmzQhr9NhCOFb2VPj0gTs,10061
|
|
47
|
+
mGST/reporting/figure_gen.py,sha256=xFPAHx1Trdqz7swn0kRqwc_jbRaNxhG9Nvx0jeitooo,25847
|
|
48
|
+
mGST/reporting/reporting.py,sha256=Wss1-zFsMEhzrrXKfP-RICau80ezjDIzcN555KhSehc,34160
|
|
49
|
+
iqm_benchmarks-2.45.dist-info/METADATA,sha256=a121AuXxTW_ziKGmIdEd-qjjBunWeV3iFEp60U4kT9o,10905
|
|
50
|
+
iqm_benchmarks-2.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
iqm_benchmarks-2.45.dist-info/top_level.txt,sha256=3G23Z-1LGf-IOzTCUl6QwWqiQ3USz25Zt90Ihq192to,9
|
|
52
|
+
iqm_benchmarks-2.45.dist-info/RECORD,,
|
mGST/additional_fns.py
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
Utility functions used by mGST modules
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import os
|
|
6
7
|
import random
|
|
8
|
+
import sys
|
|
7
9
|
import warnings
|
|
8
10
|
|
|
9
11
|
import numpy as np
|
|
@@ -13,6 +15,18 @@ from scipy.linalg import expm, qr
|
|
|
13
15
|
from mGST.low_level_jit import Mp_norm_lower, MVE_lower, contract, local_basis
|
|
14
16
|
|
|
15
17
|
|
|
18
|
+
@contextlib.contextmanager
|
|
19
|
+
def suppress_stdout():
|
|
20
|
+
"""Context manager to temporarily suppress stdout output."""
|
|
21
|
+
with open(os.devnull, "w", encoding="utf-8") as devnull:
|
|
22
|
+
old_stdout = sys.stdout
|
|
23
|
+
sys.stdout = devnull
|
|
24
|
+
try:
|
|
25
|
+
yield
|
|
26
|
+
finally:
|
|
27
|
+
sys.stdout = old_stdout
|
|
28
|
+
|
|
29
|
+
|
|
16
30
|
def transp(dim1, dim2):
|
|
17
31
|
"""Superoperator of a map that performs the transpose operation
|
|
18
32
|
|
|
@@ -261,6 +275,10 @@ def random_gs(d, r, rK, n_povm):
|
|
|
261
275
|
The second axis enumerates Kraus operators for a gate specified by the first axis.
|
|
262
276
|
X: 3D numpy array
|
|
263
277
|
Array where random CPT superoperators are stacked along the first axis.
|
|
278
|
+
E: 2D numpy array
|
|
279
|
+
Randomly generated POVM elements stacked along the first axis.
|
|
280
|
+
rho: 1D numpy array
|
|
281
|
+
Random initial state vector
|
|
264
282
|
|
|
265
283
|
Notes:
|
|
266
284
|
The Kraus operators are generated from random unitaries, see function randKrausSet
|
|
@@ -327,7 +345,7 @@ def perturbed_target_init(X_target, rK):
|
|
|
327
345
|
"""
|
|
328
346
|
d, r, _ = X_target.shape
|
|
329
347
|
pdim = int(np.sqrt(r))
|
|
330
|
-
K_perturb = randKrausSet(d, r, rK, a=0.
|
|
348
|
+
K_perturb = randKrausSet(d, r, rK, a=0.05)
|
|
331
349
|
X_perturb = np.einsum("ijkl,ijnm -> iknlm", K_perturb, K_perturb.conj()).reshape((d, r, r))
|
|
332
350
|
X_init = np.einsum("ikl,ilm ->ikm", X_perturb, X_target)
|
|
333
351
|
K_init = Kraus_rep(X_init, d, pdim, rK)
|
|
@@ -627,8 +645,7 @@ def sampled_measurements(y, n):
|
|
|
627
645
|
y_new = np.maximum(np.minimum(y, 1), 0)
|
|
628
646
|
if np.sum(np.abs(y_new - y)) > 1e-6:
|
|
629
647
|
warnings.warn(
|
|
630
|
-
f"Warning: Probabilities capped to interval [0,1]"
|
|
631
|
-
f"l1-difference to input:%f" % np.sum(np.abs(y_new - y)),
|
|
648
|
+
f"Warning: Probabilities capped to interval [0,1], l1-difference to input: {np.sum(np.abs(y_new - y))}"
|
|
632
649
|
)
|
|
633
650
|
y = y_new
|
|
634
651
|
rng = np.random.default_rng()
|
|
@@ -723,24 +740,22 @@ def is_positive(X, E, rho):
|
|
|
723
740
|
eigvals = np.array([la.eigvals(X_choi[i]) for i in range(d)])
|
|
724
741
|
partial_traces = np.einsum("aiikl -> akl", X.reshape(d, pdim, pdim, pdim, pdim))
|
|
725
742
|
povm_eigvals = np.array([la.eigvals(E[i].reshape(pdim, pdim)) for i in range(n_povm)])
|
|
726
|
-
if np.any(np.imag(eigvals.reshape(-1) > 1e-10)):
|
|
727
|
-
print("Gates are not all hermitian.")
|
|
728
|
-
else:
|
|
729
|
-
for i in range(d):
|
|
730
|
-
print(f"Gate %i positive:" % i, np.all(eigvals[i, :] > -1e-10))
|
|
731
|
-
print(f"Gate %i trace preserving:" % i, la.norm(partial_traces[i] - np.eye(pdim)) < 1e-10)
|
|
732
|
-
print(f"Initial state positive:", np.all(la.eigvals(rho.reshape(pdim, pdim)) > -1e-10))
|
|
733
|
-
print(f"Initial state normalization:", np.trace(rho.reshape(pdim, pdim)))
|
|
734
|
-
print(
|
|
735
|
-
"fPOVM valid:",
|
|
736
|
-
np.all(
|
|
737
|
-
[
|
|
738
|
-
la.norm(np.sum(E, axis=0).reshape(pdim, pdim) - np.eye(pdim)) < 1e-10,
|
|
739
|
-
np.all(povm_eigvals.reshape(-1) > -1e-10),
|
|
740
|
-
]
|
|
741
|
-
),
|
|
742
|
-
)
|
|
743
743
|
|
|
744
|
+
# Check if gates are hermitian
|
|
745
|
+
assert np.all(np.imag(eigvals.reshape(-1)) < 1e-10)
|
|
746
|
+
|
|
747
|
+
# Check if gates are positive and trace preserving
|
|
748
|
+
for i in range(d):
|
|
749
|
+
assert np.all(eigvals[i, :] > -1e-10)
|
|
750
|
+
assert la.norm(partial_traces[i] - np.eye(pdim)) < 1e-10
|
|
751
|
+
|
|
752
|
+
# Initial state positivity and normalization
|
|
753
|
+
assert np.all(la.eigvals(rho.reshape(pdim, pdim)) > -1e-10)
|
|
754
|
+
assert np.abs(np.trace(rho.reshape(pdim, pdim))) - 1 < 1e-10
|
|
755
|
+
|
|
756
|
+
# POVM positivity and normalization
|
|
757
|
+
assert la.norm(np.sum(E, axis=0).reshape(pdim, pdim) - np.eye(pdim)) < 1e-6
|
|
758
|
+
assert np.all(povm_eigvals.reshape(-1) > -1e-10)
|
|
744
759
|
|
|
745
760
|
def tvd(X, E, rho, J, y_data):
|
|
746
761
|
"""Return the total variation distance between model probabilities for the circuits in J
|
mGST/algorithm.py
CHANGED
|
@@ -28,7 +28,7 @@ from mGST.optimization import (
|
|
|
28
28
|
from mGST.reporting.figure_gen import plot_objf
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
31
|
+
def A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3, mle=False):
|
|
32
32
|
"""Riemannian saddle free Newton step on the POVM parametrization
|
|
33
33
|
|
|
34
34
|
Parameters
|
|
@@ -73,7 +73,7 @@ def A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
|
73
73
|
Fyy = np.zeros((n_povm, r, n_povm, r)).astype(np.complex128)
|
|
74
74
|
|
|
75
75
|
X = np.einsum("ijkl,ijnm -> iknlm", K, K.conj()).reshape((d, r, r))
|
|
76
|
-
dA_, dMdM, dMconjdM, dconjdA = ddA_derivs(X, A, B, J, y, r, pdim, n_povm)
|
|
76
|
+
dA_, dMdM, dMconjdM, dconjdA = ddA_derivs(X, A, B, J, y, r, pdim, n_povm, mle=mle)
|
|
77
77
|
|
|
78
78
|
# Second derivatives
|
|
79
79
|
for i in range(n_povm):
|
|
@@ -133,12 +133,12 @@ def A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
|
133
133
|
|
|
134
134
|
Delta = tangent_proj(A, Delta_A, 1, n_povm)[0]
|
|
135
135
|
|
|
136
|
-
a = minimize(lineobjf_A_geodesic, 1e-9, args=(Delta, X, A, rho, J, y), method="COBYLA").x
|
|
136
|
+
a = minimize(lineobjf_A_geodesic, 1e-9, args=(Delta, X, A, rho, J, y, mle), method="COBYLA").x
|
|
137
137
|
A_new = update_A_geodesic(A, Delta, a)
|
|
138
138
|
return A_new
|
|
139
139
|
|
|
140
140
|
|
|
141
|
-
def B_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
141
|
+
def B_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3, mle=False):
|
|
142
142
|
"""Riemannian saddle free Newton step on the initial state parametrization
|
|
143
143
|
|
|
144
144
|
Parameters
|
|
@@ -180,11 +180,9 @@ def B_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
|
180
180
|
E = np.array([(A[i].T.conj() @ A[i]).reshape(-1) for i in range(n_povm)])
|
|
181
181
|
H = np.zeros((2, nt, 2, nt)).astype(np.complex128)
|
|
182
182
|
P_T = np.zeros((2, nt, 2, nt)).astype(np.complex128)
|
|
183
|
-
Fyconjy = np.zeros((r, r)).astype(np.complex128)
|
|
184
|
-
Fyy = np.zeros((r, r)).astype(np.complex128)
|
|
185
183
|
|
|
186
184
|
X = np.einsum("ijkl,ijnm -> iknlm", K, K.conj()).reshape((d, r, r))
|
|
187
|
-
dB_, dMdM, dMconjdM, dconjdB = ddB_derivs(X, A, B, J, y, r, pdim)
|
|
185
|
+
dB_, dMdM, dMconjdM, dconjdB = ddB_derivs(X, A, B, J, y, r, pdim, mle=mle)
|
|
188
186
|
|
|
189
187
|
# Second derivatives
|
|
190
188
|
Fyconjy = dMconjdM + dconjdB
|
|
@@ -241,14 +239,15 @@ def B_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, lam=1e-3):
|
|
|
241
239
|
Delta = (H_abs_inv @ G)[:nt]
|
|
242
240
|
# Projection onto tangent space
|
|
243
241
|
Delta = Delta - Y * (Y.T.conj() @ Delta + Delta.T.conj() @ Y) / 2
|
|
244
|
-
res = minimize(
|
|
242
|
+
res = minimize(
|
|
243
|
+
lineobjf_B_geodesic, 1e-9, args=(Delta, X, E, B, J, y, mle), method="COBYLA", options={"maxiter": 20}
|
|
244
|
+
)
|
|
245
245
|
a = res.x
|
|
246
|
-
|
|
247
246
|
B_new = update_B_geodesic(B, Delta, a)
|
|
248
247
|
return B_new
|
|
249
248
|
|
|
250
249
|
|
|
251
|
-
def gd(K, E, rho, y, J, d, r, rK, fixed_gates, ls="COBYLA"):
|
|
250
|
+
def gd(K, E, rho, y, J, d, r, rK, fixed_gates, ls="COBYLA", mle=False):
|
|
252
251
|
"""Do Riemannian gradient descent optimization step on gates
|
|
253
252
|
|
|
254
253
|
Parameters
|
|
@@ -291,7 +290,7 @@ def gd(K, E, rho, y, J, d, r, rK, fixed_gates, ls="COBYLA"):
|
|
|
291
290
|
Delta = np.zeros((d, n, pdim)).astype(np.complex128)
|
|
292
291
|
X = np.einsum("ijkl,ijnm -> iknlm", K, K.conj()).reshape((d, r, r))
|
|
293
292
|
|
|
294
|
-
dK_ = dK(X, K, E, rho, J, y, d, r, rK)
|
|
293
|
+
dK_ = dK(X, K, E, rho, J, y, d, r, rK, mle=mle)
|
|
295
294
|
for k in np.where(~fixed_gates)[0]:
|
|
296
295
|
# derivative
|
|
297
296
|
Fy = dK_[k].reshape(n, pdim)
|
|
@@ -299,14 +298,20 @@ def gd(K, E, rho, y, J, d, r, rK, fixed_gates, ls="COBYLA"):
|
|
|
299
298
|
# Riem. gradient taken from conjugate derivative
|
|
300
299
|
rGrad = 2 * (Fy.conj() - Y @ Fy.T @ Y)
|
|
301
300
|
Delta[k] = rGrad
|
|
302
|
-
|
|
301
|
+
|
|
302
|
+
# Additional projection onto tangent space to avoid numerical instability
|
|
303
|
+
Delta = tangent_proj(K, Delta, d, rK)
|
|
304
|
+
|
|
305
|
+
res = minimize(
|
|
306
|
+
lineobjf_isom_geodesic, 1e-8, args=(Delta, K, E, rho, J, y, mle), method=ls, options={"maxiter": 200}
|
|
307
|
+
)
|
|
303
308
|
a = res.x
|
|
304
309
|
K_new = update_K_geodesic(K, Delta, a)
|
|
305
310
|
|
|
306
311
|
return K_new
|
|
307
312
|
|
|
308
313
|
|
|
309
|
-
def SFN_riem_Hess(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", fixed_gates=None):
|
|
314
|
+
def SFN_riem_Hess(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", fixed_gates=None, mle=False):
|
|
310
315
|
"""Riemannian saddle free Newton step on each gate individually
|
|
311
316
|
|
|
312
317
|
Parameters
|
|
@@ -355,8 +360,8 @@ def SFN_riem_Hess(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", fixed_gates=
|
|
|
355
360
|
fixed_gates = []
|
|
356
361
|
|
|
357
362
|
# compute derivatives
|
|
358
|
-
dK_, dM10, dM11 = dK_dMdM(X, K, E, rho, J, y, d, r, rK)
|
|
359
|
-
dd, dconjd = ddM(X, K, E, rho, J, y, d, r, rK)
|
|
363
|
+
dK_, dM10, dM11 = dK_dMdM(X, K, E, rho, J, y, d, r, rK, mle=mle)
|
|
364
|
+
dd, dconjd = ddM(X, K, E, rho, J, y, d, r, rK, mle=mle)
|
|
360
365
|
|
|
361
366
|
# Second derivatives
|
|
362
367
|
Fyconjy = dM11.reshape(d, nt, d, nt) + np.einsum("ijklmnop->ikmojlnp", dconjd).reshape((d, nt, d, nt))
|
|
@@ -408,14 +413,16 @@ def SFN_riem_Hess(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", fixed_gates=
|
|
|
408
413
|
|
|
409
414
|
Delta = tangent_proj(K, Delta_K, d, rK)
|
|
410
415
|
|
|
411
|
-
res = minimize(
|
|
416
|
+
res = minimize(
|
|
417
|
+
lineobjf_isom_geodesic, 1e-8, args=(Delta, K, E, rho, J, y, mle), method=ls, options={"maxiter": 200}
|
|
418
|
+
)
|
|
412
419
|
a = res.x
|
|
413
420
|
K_new = update_K_geodesic(K, Delta, a)
|
|
414
421
|
|
|
415
422
|
return K_new
|
|
416
423
|
|
|
417
424
|
|
|
418
|
-
def SFN_riem_Hess_full(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA"):
|
|
425
|
+
def SFN_riem_Hess_full(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", mle=False):
|
|
419
426
|
"""Riemannian saddle free Newton step on product manifold of all gates
|
|
420
427
|
|
|
421
428
|
Parameters
|
|
@@ -459,8 +466,8 @@ def SFN_riem_Hess_full(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA"):
|
|
|
459
466
|
X = np.einsum("ijkl,ijnm -> iknlm", K, K.conj()).reshape((d, r, r))
|
|
460
467
|
|
|
461
468
|
# compute derivatives
|
|
462
|
-
dK_, dM10, dM11 = dK_dMdM(X, K, E, rho, J, y, d, r, rK)
|
|
463
|
-
dd, dconjd = ddM(X, K, E, rho, J, y, d, r, rK)
|
|
469
|
+
dK_, dM10, dM11 = dK_dMdM(X, K, E, rho, J, y, d, r, rK, mle=mle)
|
|
470
|
+
dd, dconjd = ddM(X, K, E, rho, J, y, d, r, rK, mle=mle)
|
|
464
471
|
|
|
465
472
|
# Second derivatives
|
|
466
473
|
Fyconjy = dM11.reshape(d, nt, d, nt) + np.einsum("ijklmnop->ikmojlnp", dconjd).reshape((d, nt, d, nt))
|
|
@@ -522,13 +529,13 @@ def SFN_riem_Hess_full(K, E, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA"):
|
|
|
522
529
|
|
|
523
530
|
# Delta_K is already in tangent space but not to sufficient numerical accuracy
|
|
524
531
|
Delta = tangent_proj(K, Delta_K, d, rK)
|
|
525
|
-
res = minimize(lineobjf_isom_geodesic, 1e-8, args=(Delta, K, E, rho, J, y), method=ls, options={"maxiter": 20})
|
|
532
|
+
res = minimize(lineobjf_isom_geodesic, 1e-8, args=(Delta, K, E, rho, J, y, mle), method=ls, options={"maxiter": 20})
|
|
526
533
|
a = res.x
|
|
527
534
|
K_new = update_K_geodesic(K, Delta, a)
|
|
528
535
|
return K_new
|
|
529
536
|
|
|
530
537
|
|
|
531
|
-
def optimize(y, J, d, r, rK, n_povm, method, K, rho, A, B, fixed_elements):
|
|
538
|
+
def optimize(y, J, d, r, rK, n_povm, method, K, rho, A, B, fixed_elements, mle=False):
|
|
532
539
|
"""Full gate set optimization update alternating on E, K and rho
|
|
533
540
|
|
|
534
541
|
Parameters
|
|
@@ -578,27 +585,27 @@ def optimize(y, J, d, r, rK, n_povm, method, K, rho, A, B, fixed_elements):
|
|
|
578
585
|
A_new = A
|
|
579
586
|
E_new = np.array([(A_new[i].T.conj() @ A_new[i]).reshape(-1) for i in range(n_povm)])
|
|
580
587
|
else:
|
|
581
|
-
A_new = A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm)
|
|
588
|
+
A_new = A_SFN_riem_Hess(K, A, B, y, J, d, r, n_povm, mle=mle)
|
|
582
589
|
E_new = np.array([(A_new[i].T.conj() @ A_new[i]).reshape(-1) for i in range(n_povm)])
|
|
583
|
-
|
|
584
590
|
if any(((f"G%i" % i in fixed_elements) for i in range(d))):
|
|
585
591
|
fixed_gates = np.array([(f"G%i" % i in fixed_elements) for i in range(d)])
|
|
586
592
|
if method == "SFN":
|
|
587
|
-
K_new = SFN_riem_Hess(
|
|
593
|
+
K_new = SFN_riem_Hess(
|
|
594
|
+
K, E_new, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", fixed_gates=fixed_gates, mle=mle
|
|
595
|
+
)
|
|
588
596
|
else:
|
|
589
|
-
K_new = gd(K, E_new, rho, y, J, d, r, rK, ls="COBYLA", fixed_gates=fixed_gates)
|
|
597
|
+
K_new = gd(K, E_new, rho, y, J, d, r, rK, ls="COBYLA", fixed_gates=fixed_gates, mle=mle)
|
|
590
598
|
else:
|
|
591
599
|
if method == "SFN":
|
|
592
|
-
K_new = SFN_riem_Hess_full(K, E_new, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA")
|
|
600
|
+
K_new = SFN_riem_Hess_full(K, E_new, rho, y, J, d, r, rK, lam=1e-3, ls="COBYLA", mle=mle)
|
|
593
601
|
else:
|
|
594
602
|
fixed_gates = np.array([(f"G%i" % i in fixed_elements) for i in range(d)])
|
|
595
|
-
K_new = gd(K, E_new, rho, y, J, d, r, rK, fixed_gates=fixed_gates, ls="COBYLA")
|
|
596
|
-
|
|
603
|
+
K_new = gd(K, E_new, rho, y, J, d, r, rK, fixed_gates=fixed_gates, ls="COBYLA", mle=mle)
|
|
597
604
|
if "rho" in fixed_elements:
|
|
598
605
|
rho_new = rho
|
|
599
606
|
B_new = B
|
|
600
607
|
else:
|
|
601
|
-
B_new = B_SFN_riem_Hess(K_new, A_new, B, y, J, d, r, n_povm, lam=1e-3)
|
|
608
|
+
B_new = B_SFN_riem_Hess(K_new, A_new, B, y, J, d, r, n_povm, lam=1e-3, mle=mle)
|
|
602
609
|
rho_new = (B_new @ B_new.T.conj()).reshape(-1)
|
|
603
610
|
X_new = np.einsum("ijkl,ijnm -> iknlm", K_new, K_new.conj()).reshape((d, r, r))
|
|
604
611
|
return K_new, X_new, E_new, rho_new, A_new, B_new
|
|
@@ -609,13 +616,13 @@ def run_mGST(
|
|
|
609
616
|
method="SFN",
|
|
610
617
|
max_inits=10,
|
|
611
618
|
max_iter=200,
|
|
612
|
-
final_iter=
|
|
613
|
-
target_rel_prec=1e-
|
|
614
|
-
threshold_multiplier=
|
|
619
|
+
final_iter=120,
|
|
620
|
+
target_rel_prec=1e-5,
|
|
621
|
+
threshold_multiplier=5,
|
|
615
622
|
fixed_elements=None,
|
|
616
623
|
init=None,
|
|
617
|
-
|
|
618
|
-
): # pylint: disable=too-many-branches
|
|
624
|
+
verbose_level=0,
|
|
625
|
+
): # pylint: disable=too-many-branches, too-many-statements
|
|
619
626
|
"""Main mGST routine
|
|
620
627
|
|
|
621
628
|
Parameters
|
|
@@ -653,11 +660,11 @@ def run_mGST(
|
|
|
653
660
|
|
|
654
661
|
Returns
|
|
655
662
|
-------
|
|
656
|
-
K
|
|
663
|
+
K: numpy array
|
|
657
664
|
Updated estimates of Kraus operators
|
|
658
|
-
X
|
|
665
|
+
X: numpy array
|
|
659
666
|
Updated estimates of superoperatos corresponding to K_new
|
|
660
|
-
E
|
|
667
|
+
E: numpy array
|
|
661
668
|
Updated POVM estimate
|
|
662
669
|
rho : numpy array
|
|
663
670
|
Updated initial state estimate
|
|
@@ -682,7 +689,8 @@ def run_mGST(
|
|
|
682
689
|
)
|
|
683
690
|
|
|
684
691
|
success = False
|
|
685
|
-
|
|
692
|
+
if verbose_level > 0:
|
|
693
|
+
qcvv_logger.info(f"Starting mGST optimization...")
|
|
686
694
|
|
|
687
695
|
if init:
|
|
688
696
|
K, E = (init[0], init[1])
|
|
@@ -698,8 +706,8 @@ def run_mGST(
|
|
|
698
706
|
A = np.array([la.cholesky(E[k].reshape(pdim, pdim) + 1e-14 * np.eye(pdim)).T.conj() for k in range(n_povm)])
|
|
699
707
|
B = la.cholesky(rho.reshape(pdim, pdim))
|
|
700
708
|
res_list = [objf(X, E, rho, J, y)]
|
|
701
|
-
with logging_redirect_tqdm(loggers=[qcvv_logger]):
|
|
702
|
-
for _ in trange(max_iter):
|
|
709
|
+
with logging_redirect_tqdm(loggers=[qcvv_logger] if verbose_level > 0 else None):
|
|
710
|
+
for _ in trange(max_iter, disable=verbose_level == 0):
|
|
703
711
|
yb, Jb = batch(y, J, bsize)
|
|
704
712
|
K, X, E, rho, A, B = optimize(yb, Jb, d, r, rK, n_povm, method, K, rho, A, B, fixed_elements)
|
|
705
713
|
res_list.append(objf(X, E, rho, J, y))
|
|
@@ -707,29 +715,37 @@ def run_mGST(
|
|
|
707
715
|
qcvv_logger.info(f"Batch optimization successful, improving estimate over full data....")
|
|
708
716
|
success = True
|
|
709
717
|
break
|
|
710
|
-
if
|
|
711
|
-
plot_objf(res_list,
|
|
718
|
+
if verbose_level == 2:
|
|
719
|
+
plot_objf(res_list, f"Objective function for batch optimization", delta=delta)
|
|
712
720
|
if success:
|
|
713
721
|
break
|
|
714
|
-
|
|
722
|
+
if verbose_level > 0:
|
|
723
|
+
qcvv_logger.info(f"Run {i+1}/{max_inits} failed, trying new initialization...")
|
|
715
724
|
|
|
716
|
-
if not success and
|
|
725
|
+
if not success and init is None and verbose_level > 0:
|
|
717
726
|
qcvv_logger.info(f"Success threshold not reached, attempting optimization over full data set...")
|
|
718
|
-
with logging_redirect_tqdm(loggers=[qcvv_logger]):
|
|
719
|
-
|
|
720
|
-
|
|
727
|
+
with logging_redirect_tqdm(loggers=[qcvv_logger] if verbose_level > 0 else None):
|
|
728
|
+
res_list_mle = []
|
|
729
|
+
for _ in trange(final_iter, disable=verbose_level == 0):
|
|
730
|
+
K, X, E, rho, A, B = optimize(y, J, d, r, rK, n_povm, method, K, rho, A, B, fixed_elements, mle=True)
|
|
721
731
|
res_list.append(objf(X, E, rho, J, y))
|
|
722
|
-
|
|
732
|
+
res_list_mle.append(objf(X, E, rho, J, y, mle=True))
|
|
733
|
+
if (
|
|
734
|
+
len(res_list_mle) >= 2
|
|
735
|
+
and np.abs(res_list_mle[-2] - res_list_mle[-1]) < res_list_mle[-1] * target_rel_prec
|
|
736
|
+
):
|
|
723
737
|
break
|
|
724
|
-
if
|
|
725
|
-
plot_objf(res_list,
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
738
|
+
if verbose_level == 2:
|
|
739
|
+
plot_objf(res_list, f"Least squares error over batches and full data", delta=delta)
|
|
740
|
+
plot_objf(res_list_mle, f"Negative log-likelihood over full data")
|
|
741
|
+
if verbose_level > 0:
|
|
742
|
+
if success or (res_list[-1] < delta):
|
|
743
|
+
qcvv_logger.info(f"Convergence criterion satisfied")
|
|
744
|
+
else:
|
|
745
|
+
qcvv_logger.warning(
|
|
746
|
+
f"Convergence criterion not satisfied. Potential causes include too low max_iterations, bad initialization or model mismatch."
|
|
747
|
+
)
|
|
729
748
|
qcvv_logger.info(
|
|
730
|
-
f"
|
|
749
|
+
f"Final objective {Decimal(res_list[-1]):.2e} in time {(time.time() - t0):.2f}s",
|
|
731
750
|
)
|
|
732
|
-
qcvv_logger.info(
|
|
733
|
-
f"Final objective {Decimal(res_list[-1]):.2e} in time {(time.time() - t0):.2f}s",
|
|
734
|
-
)
|
|
735
751
|
return K, X, E, rho, res_list
|