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

1from .matrix_utils import * 

2import scipy 

3from scipy.linalg import expm 

4import math 

5 

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 

15 

16 

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) 

23 

24 R = expm(-t * X) 

25 R = R/np.trace(X) 

26 

27 return R 

28 

29 

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)))) 

34 

35 

36def js_divergence(A, B, t, return_partial_entropies=True): 

37 X = get_density_matrix(A, t) 

38 Y = get_density_matrix(B, t) 

39 

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)) 

43 

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 

51 

52 if not return_partial_entropies: 

53 return JSD 

54 else: 

55 return manual_entropy(mixed), ent1, ent2, JSD