|
| 1 | +# Quandary's python interface functions are defined in /path/to/quandary/quandary.py. Import them here. |
| 2 | +from quandary import * |
| 3 | +np.random.seed(9001) |
| 4 | + |
| 5 | +### Define some case's coefficients |
| 6 | +def get_deterministic_params(N, h_amp, U_amp, J_amp): |
| 7 | + h = h_amp * np.ones(N) |
| 8 | + U = U_amp * np.ones(N-1) |
| 9 | + J = J_amp * np.ones(N-1) |
| 10 | + return h, U, J |
| 11 | + |
| 12 | +def get_xx_params(N, J_amp): |
| 13 | + h = np.zeros(N) |
| 14 | + U = np.zeros(N-1) |
| 15 | + J = J_amp * np.ones(N-1) |
| 16 | + return h, U, J |
| 17 | + |
| 18 | +def get_disordered_xx_params(N, h_amp, J_amp): |
| 19 | + h = np.random.uniform(-h_amp, h_amp, N) |
| 20 | + U = np.zeros(N) |
| 21 | + J = J_amp * np.ones(N) |
| 22 | + return h, U, J |
| 23 | + |
| 24 | +def get_xxz_params(N, U_amp, J_amp): |
| 25 | + h = np.zeros(N) |
| 26 | + U = U_amp * np.ones(N) |
| 27 | + J = J_amp * np.ones(N) |
| 28 | + return h, U, J |
| 29 | + |
| 30 | +def get_disordered_xxz_params(N, h_amp, U_amp, J_amp): |
| 31 | + h = np.random.uniform(-h_amp, h_amp, N) |
| 32 | + U = U_amp * np.ones(N) |
| 33 | + J = J_amp * np.ones(N) |
| 34 | + return h, U, J |
| 35 | + |
| 36 | +def mapCoeffs_SpinChainToQuandary(N:int, h:list, U:list, J:list): |
| 37 | + """ |
| 38 | + Map spin chain coefficents J, U and h onto Quandary coefficients |
| 39 | +
|
| 40 | + Parameters: |
| 41 | + ------------ |
| 42 | + N : int : number of spin sites |
| 43 | + J : float : J-coefficient per linear chain coupling: J[i] couples i and i+1 |
| 44 | + U : list(float) : U-coefficient per linear chain coupling: J[i] couples i and i+1 |
| 45 | + h : list(float) : h-coefficient per spin site |
| 46 | + |
| 47 | + Output: |
| 48 | + -------- |
| 49 | + freq01 : 01-transition frequency per qubit (omega_j) |
| 50 | + crossker : crossker coupling (linear chain) (xi_ij) |
| 51 | + Jkl : dipole-dipole coupling (linear chain) (J_ij) |
| 52 | + """ |
| 53 | + |
| 54 | + # 01 transition frequencies [GHz] per site (omega_q) |
| 55 | + freq01 = np.zeros(N) |
| 56 | + for i in range(1,N-1): |
| 57 | + freq01[i] = (-2*h[i] -2*U[i] -2*U[i-1]) / (2*np.pi) |
| 58 | + freq01[0] = (-2*h[0] - 2*U[0] ) / (2*np.pi) |
| 59 | + freq01[N-1] = (-2*h[N-1] - 2*U[N-2]) / (2*np.pi) |
| 60 | + # Jkl and Xi term [GHz] (Format [0<->1, 0<->2, ..., 1<->2, ... ]) |
| 61 | + Jkl=[] |
| 62 | + crosskerr=[] |
| 63 | + couplingID = 0 |
| 64 | + for i in range(N): |
| 65 | + for j in range(i+1, N): |
| 66 | + if j == i+1: # linear chain coupling |
| 67 | + valJ = - 2*J[couplingID] / (2*np.pi) |
| 68 | + valC = - 4*U[couplingID] / (2*np.pi) |
| 69 | + else: |
| 70 | + valJ = 0.0 |
| 71 | + valC = 0.0 |
| 72 | + Jkl.append(valJ) |
| 73 | + crosskerr.append(valC) |
| 74 | + couplingID += 1 |
| 75 | + return freq01, crosskerr, Jkl |
| 76 | +##### |
| 77 | + |
| 78 | +# Specify the number of spin sites |
| 79 | +N = 8 |
| 80 | + |
| 81 | +# Get spin chain case coefficients |
| 82 | +U_amp = 1.0 |
| 83 | +J_amp = 1.0 |
| 84 | +h_amp = 1.0 |
| 85 | +h, U, J = get_disordered_xx_params(N, U_amp, J_amp) |
| 86 | + |
| 87 | +# Specify the initial state (list of 0 or 1 per site). Here: domain wall |111...000> |
| 88 | +initstate= np.zeros(N, dtype=int) |
| 89 | +for i in range(int(N/2)): |
| 90 | + initstate[i] = 1 |
| 91 | + |
| 92 | +# Set the simulation duration and step size |
| 93 | +T = 10.0 |
| 94 | +# T = 4.0 |
| 95 | +dT = 0.01 # Double check if this is small enough (e.g. by re-running with smaller dT and compare results) |
| 96 | + |
| 97 | +# Quandary run options |
| 98 | +verbose = True |
| 99 | +ncores=8 # Numbers of cores for Quandary |
| 100 | +mpirun = "mpirun -np " # MPI executable, e.g. "srun -n" for LC (note the space after '-np ' for mpirun vs no space after '-n' for srun) |
| 101 | + |
| 102 | +# Prepare Quandary |
| 103 | +initcondstr = "pure, " |
| 104 | +for e in initstate: |
| 105 | + initcondstr += str(e) +", " |
| 106 | +freq01, crosskerr, Jkl = mapCoeffs_SpinChainToQuandary(N, h, U, J) |
| 107 | +quandary = Quandary(Ne=[2 for _ in range(N)], Ng=[0 for _ in range(N)], freq01=freq01, rotfreq=np.zeros(N), crosskerr=crosskerr, Jkl=Jkl, initialcondition=initcondstr, T=T, dT=dT, initctrl_MHz=0.0, carrier_frequency=[[0.0] for _ in range(N)], verbose=verbose) |
| 108 | + |
| 109 | +# Storage for averaged magnetization. Matrix rows = sites, cols = time |
| 110 | +magnet = np.zeros((N,quandary.nsteps+1)) |
| 111 | +# Storage for averaged domain wall spread |
| 112 | +nhalf = np.zeros(quandary.nsteps+1) |
| 113 | + |
| 114 | +# Number of samples for h |
| 115 | +# nsamples = 10 |
| 116 | +nsamples = 1 |
| 117 | + |
| 118 | +# Iterate over randomized h and run quandary |
| 119 | +for isample in range(nsamples): |
| 120 | + |
| 121 | + # Sample new set of coefficients and map to Quandary's coeffs |
| 122 | + h, U, J = get_disordered_xx_params(N, U_amp, J_amp) |
| 123 | + quandary.freq01, quandary.crosskerr, quandary.Jkl = mapCoeffs_SpinChainToQuandary(N, h, U, J) |
| 124 | + quandary.update() |
| 125 | + |
| 126 | + # Run forward simulation |
| 127 | + datadir = "./N"+str(N)+"_sample" + str(isample)+"_run_dir_parallel" |
| 128 | + t, pt, qt, infidelity, expectedEnergy, population = quandary.simulate(datadir=datadir, maxcores=ncores, mpirun=mpirun) |
| 129 | + |
| 130 | + # Compute magnetization from expected Energy (-2*expEnergy + 1) and add to average |
| 131 | + for isite in range(N): |
| 132 | + for nt in range(len(t)): |
| 133 | + exp = expectedEnergy[isite][0][nt] ## expected energy for this site and time |
| 134 | + magnet_this = -2.0*exp + 1.0 |
| 135 | + magnet[isite,nt] += magnet_this / nsamples |
| 136 | + |
| 137 | + # Compute domain wall spread (N_1/2) from expected Energy and add to average |
| 138 | + for nt in range(len(t)): # iterate over time |
| 139 | + nhalf_i = 0.0 |
| 140 | + for isite in range(int(N/2)): # iterate over first half of the sites |
| 141 | + nhalf_i -= expectedEnergy[isite][0][nt] |
| 142 | + nhalf_i += int(N/2) |
| 143 | + nhalf[nt] += nhalf_i / nsamples |
| 144 | + |
| 145 | +# # Plot sigmaz dynamics of one spin site |
| 146 | +# isite = 0 |
| 147 | +# myexp = [-2*e+1 for e in expectedEnergy[isite][0]] |
| 148 | +# plt.plot(t, myexp) |
| 149 | +# plt.show() |
| 150 | + |
| 151 | +# Plot heatmap of magnetization |
| 152 | +fig, ax = plt.subplots(figsize=(6,4)) |
| 153 | +mycmap = plt.get_cmap('coolwarm') |
| 154 | +plt.imshow(magnet, interpolation='none', aspect='auto', cmap=mycmap) |
| 155 | +plt.colorbar() |
| 156 | +plt.title(r"Heat Map of Spin Chain $\langle \sigma^z_j \rangle$") |
| 157 | +plt.xlabel("Time-step index") |
| 158 | +plt.ylabel("Spin Site Index $j$") |
| 159 | +plt.show() |
| 160 | + |
| 161 | +# Plot domain wall spread: |
| 162 | +plt.plot(t, nhalf) |
| 163 | +plt.xlabel("Time-step index") |
| 164 | +plt.ylabel("N_1/2") |
| 165 | +plt.grid(True) |
| 166 | +plt.legend() |
| 167 | +plt.show() |
| 168 | + |
0 commit comments