Coverage for src/driada/network/quantum.py: 20.51%
39 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-25 15:40 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-25 15:40 +0300
1from .matrix_utils import *
2import scipy
3from scipy.linalg import expm
4import math
6def renyi_divergence(A, B, q):
7 if q <= 0:
8 raise Exception('q must be >0')
9 elif q == 1:
10 answer = np.trace(np.dot(A, (scipy.linalg.logm(A) - scipy.linalg.logm(B))/np.log(2.0)))
11 else:
12 answer = (1/(q-1)) * np.log(np.trace(np.dot(scipy.linalg.fractional_matrix_power(A, q),
13 scipy.linalg.fractional_matrix_power(B, 1-q))))/np.log(2.0)
14 return answer
17def get_density_matrix(A, t, norm=0):
18 A = A.astype(float)
19 if norm:
20 X = get_norm_laplacian(A)
21 else:
22 X = get_laplacian(A)
24 R = expm(-t * X)
25 R = R/np.trace(X)
27 return R
30def manual_entropy(pr):
31 probs = np.trim_zeros(pr)
32 probs = probs[np.where(probs > 1e-15)]
33 return -np.real(np.sum(np.multiply(probs, np.log2(probs))))
36def js_divergence(A, B, t, return_partial_entropies=True):
37 X = get_density_matrix(A, t)
38 Y = get_density_matrix(B, t)
40 mixed = np.trim_zeros(np.linalg.eigvalsh((X + Y) / 2))
41 raw1 = np.trim_zeros(np.linalg.eigvalsh(X))
42 raw2 = np.trim_zeros(np.linalg.eigvalsh(Y))
44 first = manual_entropy(mixed)
45 ent1, ent2 = manual_entropy(raw1), manual_entropy(raw2)
46 second = 0.5*(ent1 + ent2)
47 try:
48 JSD = math.sqrt(first - second)
49 except:
50 JSD = 0
52 if not return_partial_entropies:
53 return JSD
54 else:
55 return manual_entropy(mixed), ent1, ent2, JSD