-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
108 lines (79 loc) · 3.71 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
from qiskit.circuit.library import UnitaryGate
from qiskit import QuantumCircuit
from scipy.linalg import expm
import numpy as np
from Shadow_Spectro.ClassicalShadow import ClassicalShadow
from Shadow_Spectro.Spectroscopy import Spectroscopy
from Shadow_Spectro.ShadowSpectro import ShadowSpectro
def Generate_Unitary_Hermitian_Matrix(numQbits,eigenvalues):
"""
Generate a Hermitian matrix with specified eigenvalues.
Args:
eigenvalues (list or np.ndarray): A list of desired eigenvalues.
Returns:
np.ndarray: A Hermitian matrix with the given eigenvalues.
"""
diagonal_matrix = np.identity(2**numQbits)
k=0
for eigenvalue, multiplicity in eigenvalues:
for i in range(multiplicity):
diagonal_matrix[k+i][k+i]=eigenvalue
k+=multiplicity
# Generate a random unitary matrix (P)
random_matrix = np.random.randn(2**numQbits, 2**numQbits) + 1j * np.random.randn(2**numQbits, 2**numQbits)
Q, _ = np.linalg.qr(random_matrix) # QR decomposition to get a unitary matrix
# Construct the Hermitian matrix: H = P \Lambda P^†
hermitian_matrix = Q @ diagonal_matrix @ Q.conj().T
return hermitian_matrix
def Generate_Evolution_Matrix(hermitian_matrix:np.ndarray):
"""Frome a given hermitian matrix
generate an evolution matrix as U(t)= exp(-iHt)
Args:
hermitian_matrix (np.ndarray): The Hermitian matrix
Returns:
function : A function of the time Unitary Gate evolution matrix
"""
hamil=(lambda t: UnitaryGate(expm(-1.j*hermitian_matrix*t)))
return hamil
if __name__=='__main__':
# parameters
eigenvalues=[(2,2**5),(8,2**5)]
Energy_gap=6 #rad/s
numQbits=6
Nt=200
dt=0.21 #s
T = np.linspace(0,Nt*dt,Nt)#
shadow_size= 10
# Generate hermitian matrix and evolution matrix
hermitian_matrix=Generate_Unitary_Hermitian_Matrix(numQbits,eigenvalues)
evolution_matrix=Generate_Evolution_Matrix(hermitian_matrix)
# Initialize the shadow and spectroscopy objects
shadow=ClassicalShadow()
spectro= Spectroscopy(Nt,dt)
shadow_spectro=ShadowSpectro(shadow,spectro, numQbits,3)
D=[]
for t in T:
C= QuantumCircuit(numQbits)
C.append(evolution_matrix(t),[i for i in range(numQbits)])
Clifford_array, bits_array=[],[]
for i in range(shadow_size): #add a clifford gate to all the qubits and measure, this is done "shadow size" times.
Clifford_gates, bits_string=shadow.classical_shadow(C)
Clifford_array.append(Clifford_gates)
bits_array.append(bits_string)
fkt=shadow_spectro.expectation_value_q_Pauli(Clifford_array,bits_array) # calculate from the shadow snapshot the expectation value of all the q-pauli-observable
D.append(fkt.tolist())
D=np.array(D)
D= spectro.Ljung_Box_test(shadow_spectro.standardisation(D))
C=shadow_spectro.reduction(D)
solution, frequencies=shadow_spectro.shadow_spectro()
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(frequencies, solution, color='blue', label=f"Spectral cross correlation")
plt.axvline(x=Energy_gap, color='black', linestyle='--', linewidth=1, label=f"Real Energie Gap: {Energy_gap:.2f} rad/s")
plt.text(Energy_gap, max(solution)*1.01, f"{Energy_gap:.2f} (rad/s)", color='Black', ha='left', va='center', fontsize=10)
# Enhance aesthetics
plt.grid(True, linestyle='--', color='gray', linewidth=0.5, alpha=0.7)
plt.title(f"Spectral Cross-Correlation", fontsize=14, fontweight='bold')
plt.xlabel("Frequency (rad/s)", fontsize=12)
plt.ylabel("Amplitude", fontsize=12)
plt.legend(fontsize=10, loc="best")