raj-dahya commited on
Commit
d52e6fe
·
verified ·
1 Parent(s): 8735d62

staging > main: refactored numerical experiment as module

Browse files
src/experiments/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Module containing experiments
6
+ """
src/experiments/choi_cholesky/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Module containing experiments for Choi--Cholesky decomposition
6
+ """
7
+
8
+ # ----------------------------------------------------------------
9
+ # IMPORTS
10
+ # ----------------------------------------------------------------
11
+
12
+ from .verify import *
13
+
14
+ # ----------------------------------------------------------------
15
+ # EXPORTS
16
+ # ----------------------------------------------------------------
17
+
18
+ __all__ = [
19
+ "verify_choi_cholesky",
20
+ ]
src/experiments/choi_cholesky/verify.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ - author: Raj Dahya
6
+ - institute: Universität Leipzig
7
+ - department: Fakultät für Mathematik und Informatik
8
+ - created: 2025-12-27
9
+ - updated: 2026-03-29
10
+ - description:
11
+ Verifies the Choi-Cholesky decomposition of a CP/CPTP map numerically,
12
+ as presented in the paper _The Choi-Cholesky algorithm for completely positive maps_
13
+ (see <https://arxiv.org/abs/2603.19444>).
14
+
15
+ Verification occurs by running the experiment multiple times without failure.
16
+
17
+ Failure criteria:
18
+
19
+ - [critical] algorithm fails to produce positive entries for the diagonal operator (within tolerance)
20
+ - in final result L·L^* is not close to Choi matrix
21
+
22
+ NOTE: Due to the discontinuous nature of pseudo-inverses (cf Remark 3.3 in §3),
23
+ the algorithm can get close to a critical error under low numerical precision (e.g. Float32).
24
+ For this reason we use double precision (Float64) numbers.
25
+
26
+ NOTE: The option `map_kind = "CP"` establishes a proper confirmation.
27
+ For completeness we have included the option `"CPTP"`,
28
+ but this provides a circular test, as the generation of CPTP-maps here assumes results of paper in advance.
29
+
30
+ """
31
+
32
+ # ----------------------------------------------------------------
33
+ # IMPORTS
34
+ # ----------------------------------------------------------------
35
+
36
+ import logging
37
+
38
+ import torch
39
+ from tabulate import tabulate
40
+
41
+ from ..._core.utils.linalg import *
42
+ from ...algorithms.choi_cholesky import *
43
+ from ...algorithms.constants import *
44
+ from ...algorithms.generation import *
45
+
46
+ # ----------------------------------------------------------------
47
+ # SETTINGS, CONSTANTS
48
+ # ----------------------------------------------------------------
49
+
50
+ TOL = 1e-6
51
+ # PRECISION = torch.float32 # works but to lower precision
52
+ PRECISION = torch.float64
53
+ # PRECISION = torch.double # same as f64
54
+
55
+ # ----------------------------------------------------------------
56
+ # EXECUTION
57
+ # ----------------------------------------------------------------
58
+
59
+
60
+ def verify_choi_cholesky(
61
+ *,
62
+ d1: int,
63
+ d2: int,
64
+ num_experiments: int,
65
+ map_kind: MAP_CATEGORY,
66
+ algorithm_choice: ALGORITHM_CHOICE,
67
+ ):
68
+ """
69
+ Experimental verification of Choi--Cholesky decomposition of CP-/CPTP-maps
70
+ """
71
+ # execute main method
72
+ tol = TOL
73
+ diffs: list[float] = []
74
+ for index in range(1, 1 + num_experiments):
75
+ logging.info(f"run experiment {index}")
76
+
77
+ """
78
+ Create a random CP/CPTP-map
79
+ """
80
+
81
+ match map_kind:
82
+ case "CPTP":
83
+ logging.info("generate Choi matrix C of a random CPTP map Φ")
84
+ C = random_cptp(d1, d2, precision=PRECISION)
85
+ diff = torch.norm(trace_2(C) - torch.eye(d1)).item()
86
+ assert diff < TOL, \
87
+ f"generated map failed to be trace preserving within tolerance {tol:.4g}" # fmt: skip
88
+ logging.info(f"generated map is trace preserving within tolerance: ‖tr₂(C) – I‖ = {diff:.4g} < {tol:.4g}") # fmt: skip
89
+
90
+ case _:
91
+ logging.info("generate Choi matrix C of a random CP map Φ")
92
+ C = random_cp(d1, d2, precision=PRECISION)
93
+
94
+ """
95
+ Perform Choi-Cholesky decomposition
96
+ """
97
+
98
+ logging.info("compute Choi-Cholesky decomposition for Φ")
99
+ match algorithm_choice:
100
+ case "CHOI-CHOLESKY-MODIFIED":
101
+ L = algorithm_choi_cholesky_modified(C, tol=TOL)
102
+
103
+ # case "CHOI-CHOLESKY":
104
+ case _:
105
+ L = algorithm_choi_cholesky(C, tol=TOL)
106
+
107
+ """
108
+ Verify validity of Choi-Cholesky decomposition
109
+ """
110
+
111
+ C_recovered = tensor_multiply(L, tensor_conj(L))
112
+ diff = tensor_diff(C, C_recovered, rel=True)
113
+ diffs.append(diff)
114
+
115
+ """
116
+ Perform statistical evaluation of success rate
117
+ """
118
+
119
+ diffs = torch.asarray(diffs)
120
+ levels = [0.25, 0.5, 0.75, 0.975]
121
+ quantiles = torch.quantile(diffs, q=torch.asarray(levels)).tolist()
122
+ table = tabulate(
123
+ zip(levels, quantiles),
124
+ headers=("quantile", "Diff"),
125
+ tablefmt="rst",
126
+ colalign=("right", "right"),
127
+ floatfmt=(".2%", ".3e"),
128
+ )
129
+ logging.info(f"quantiles for rel. differences ‖L·L^* – C(Φ)‖/‖C(Φ)‖:\n{table}")
130
+ diff = diffs[-1] # get 97.5% quantile of rel differences
131
+ assert diff < 0.5*TOL, \
132
+ f"Algorithm failed to produce decomposition that recovers original Choi matrix within tolerance {TOL:.4g}." # fmt: skip
133
+ logging.info(f"Algorithm succeeded in producing decomposition that recovers original Choi matrix within tolerance {TOL:.4g}.") # fmt: skip
134
+ return