def wfnPropagation(iMPS, HMPO, nsteps, dt, ephtable, thresh=0, \ cleanexciton=None, prop_method="C_RK4", compress_method="svd", QNargs=None): ''' simple wavefunction propagation through Runge-Kutta methods ''' tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) ketMPS = mpslib.add(iMPS, None, QNargs=QNargs) Hset = [] # energy Vset = [] # overlap for isteps in xrange(nsteps): if isteps != 0: ketMPS = tMPS(ketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, \ QNargs=QNargs) Hset.append(mpslib.dot(mpslib.conj(ketMPS,QNargs=QNargs), \ mpslib.mapply(HMPO, ketMPS, QNargs=QNargs), QNargs=QNargs)) Vset.append(mpslib.dot(mpslib.conj(ketMPS,QNargs=QNargs), \ ketMPS, QNargs=QNargs)) return Hset, Vset
def ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c, thresh=0, \ compress_method="svd", QNargs=None): ''' e^-iHdt : approximate propagator MPO from Runge-Kutta methods ''' # Identity operator if QNargs is not None: nmpo = len(HMPO[0]) else: nmpo = len(HMPO) MPOdim = [1] * (nmpo + 1) MPOQN = [[0]] * (nmpo + 1) MPOQNidx = nmpo - 1 MPOQNtot = 0 IMPO = [] for impo in xrange(nmpo): if QNargs is not None: mpo = np.ones([1, HMPO[0][impo].shape[1], 1], dtype=np.complex128) else: mpo = np.ones([1, HMPO[impo].shape[1], 1], dtype=np.complex128) IMPO.append(mpo) IMPO = hilbert_to_liouville(IMPO) QNargslocal = copy.deepcopy(QNargs) if QNargs is not None: IMPO = [IMPO, MPOQN, MPOQNidx, MPOQNtot] # a real MPO compression QNargslocal[1] = True approxMPO = tMPS(IMPO, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ compress_method=compress_method, QNargs=QNargslocal) print "approx propagator thresh:", thresh if QNargs is not None: print "approx propagator dim:", [mpo.shape[0] for mpo in approxMPO[0]] else: print "approx propagator dim:", [mpo.shape[0] for mpo in approxMPO] chkIden = mpslib.mapply(mpslib.conj(approxMPO, QNargs=QNargs), approxMPO, QNargs=QNargs) print "approx propagator Identity error", np.sqrt(mpslib.distance(chkIden, IMPO, QNargs=QNargs) /\ mpslib.dot(IMPO, IMPO, QNargs=QNargs)) return approxMPO
def FiniteT_emi(mol, pbond, iMPO, HMPO, dipoleMPO, nsteps, dt, \ ephtable, insteps, thresh=0, temperature=298, prop_method="C_RK4", compress_method="svd", QNargs=None): ''' Finite temperature emission, already included in FiniteT_spectra ''' tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) beta = constant.T2beta(temperature) ketMPO = thermal_prop(iMPO, HMPO, insteps, ephtable, prop_method=prop_method, thresh=thresh, temperature=temperature, compress_method=compress_method, QNargs=QNargs) braMPO = mpslib.add(ketMPO, None, QNargs=QNargs) #\Psi e^{\-beta H} \Psi Z = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) print "partition function Z(beta)/Z(0)", Z AketMPO = mpslib.mapply(dipoleMPO, ketMPO, QNargs=QNargs) autocorr = [] t = 0.0 ketpropMPO, ketpropMPOdim = ExactPropagatorMPO(mol, pbond, -1.0j * dt, QNargs=QNargs) dipoleMPOdagger = mpslib.conjtrans(dipoleMPO, QNargs=QNargs) if compress_method == "variational": braMPO = mpslib.canonicalise(braMPO, 'l', QNargs=QNargs) for istep in xrange(nsteps): if istep != 0: t += dt AketMPO = mpslib.mapply(ketpropMPO, AketMPO, QNargs=QNargs) braMPO = tMPS(braMPO, HMPO, dt, ephtable, propagation_c, thresh=thresh, cleanexciton=1, compress_method=compress_method, QNargs=QNargs) AAketMPO = mpslib.mapply(dipoleMPOdagger, AketMPO, QNargs=QNargs) ft = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), AAketMPO, QNargs=QNargs) autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def FiniteT_spectra(spectratype, mol, pbond, iMPO, HMPO, dipoleMPO, nsteps, dt,\ ephtable, insteps=0, thresh=0, temperature=298,\ algorithm=2, prop_method="C_RK4", compress_method="svd", QNargs=None, \ approxeiHt=None, GSshift=0.0, cleanexciton=None, scheme="P&C"): ''' finite temperature propagation only has algorithm 2, two way propagator ''' assert algorithm == 2 assert spectratype in ["abs", "emi"] tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) beta = constant.T2beta(temperature) print "beta=", beta # e^{\-beta H/2} \Psi if spectratype == "emi": ketMPO = thermal_prop(iMPO, HMPO, insteps, ephtable,\ prop_method=prop_method, thresh=thresh,\ temperature=temperature, compress_method=compress_method,\ QNargs=QNargs, approxeiHt=approxeiHt) elif spectratype == "abs": thermalMPO, thermalMPOdim = ExactPropagatorMPO(mol, pbond, -beta/2.0,\ QNargs=QNargs, shift=GSshift) ketMPO = mpslib.mapply(thermalMPO, iMPO, QNargs=QNargs) #\Psi e^{\-beta H} \Psi Z = mpslib.dot(mpslib.conj(ketMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) print "partition function Z(beta)/Z(0)", Z autocorr = [] t = 0.0 exacteiHpt, exacteiHptdim = ExactPropagatorMPO(mol, pbond, -1.0j*dt,\ QNargs=QNargs, shift=GSshift) exacteiHmt, exacteiHmtdim = ExactPropagatorMPO(mol, pbond, 1.0j*dt,\ QNargs=QNargs, shift=GSshift) if spectratype == "abs": ketMPO = mpslib.mapply(dipoleMPO, ketMPO, QNargs=QNargs) else: dipoleMPOdagger = mpslib.conjtrans(dipoleMPO, QNargs=QNargs) if QNargs is not None: dipoleMPOdagger[1] = [[0] * len(impsdim) for impsdim in dipoleMPO[1]] dipoleMPOdagger[3] = 0 ketMPO = mpslib.mapply(ketMPO, dipoleMPOdagger, QNargs=QNargs) braMPO = mpslib.add(ketMPO, None, QNargs=QNargs) if compress_method == "variational": ketMPO = mpslib.canonicalise(ketMPO, 'l', QNargs=QNargs) braMPO = mpslib.canonicalise(braMPO, 'l', QNargs=QNargs) if approxeiHt is not None: approxeiHpt = ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) approxeiHmt = ApproxPropagatorMPO(HMPO, -dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) else: approxeiHpt = None approxeiHmt = None for istep in xrange(nsteps): if istep != 0: t += dt # for emi bra and ket is conjugated if istep % 2 == 0: braMPO = mpslib.mapply(braMPO, exacteiHpt, QNargs=QNargs) braMPO = tMPS(braMPO, HMPO, -dt, ephtable, propagation_c,\ thresh=thresh, cleanexciton=1, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHmt, scheme=scheme,\ prefix=scheme+"2") else: ketMPO = mpslib.mapply(ketMPO, exacteiHmt, QNargs=QNargs) ketMPO = tMPS(ketMPO, HMPO, dt, ephtable, propagation_c, \ thresh=thresh, cleanexciton=1, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHpt, scheme=scheme,\ prefix=scheme+"1") ft = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) if spectratype == "emi": ft = np.conj(ft) wfn_store(braMPO, istep, "braMPO.pkl") wfn_store(ketMPO, istep, "ketMPO.pkl") autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def tMPS(MPS, MPO, dt, ephtable, propagation_c, thresh=0, \ cleanexciton=None, compress_method="svd", QNargs=None, approxeiHt=None,\ normalize=None, swap=False, scheme="P&C",prefix="",opt=False): ''' core function to do time propagation swap = False e^-iHt MPO swap = True MPO * e^-iHt ''' if scheme == "P&C": # propagate and compress if approxeiHt is None: termlist = [MPS] for iterm in xrange(len(propagation_c) - 1): # when using variational method, the input MPS is L-canonicalise # (in principle doesn't matter whether L-canonicalise, in practice, about # the initial guess of the compress wfn) if swap == False: termlist.append( mpslib.contract(MPO, termlist[iterm], 'l', thresh, compress_method=compress_method, QNargs=QNargs)) else: termlist.append( mpslib.contract(termlist[iterm], MPO, 'l', thresh, compress_method=compress_method, QNargs=QNargs)) scaletermlist = [] for iterm in xrange(len(propagation_c)): scaletermlist.append( mpslib.scale(termlist[iterm], (-1.0j * dt)**iterm * propagation_c[iterm], QNargs=QNargs)) MPSnew = scaletermlist[0] if opt == False: for iterm in xrange(1, len(propagation_c)): MPSnew = mpslib.add(MPSnew, scaletermlist[iterm], QNargs=QNargs) MPSnew = mpslib.canonicalise(MPSnew, 'r', QNargs=QNargs) MPSnew = mpslib.compress(MPSnew, 'r', trunc=thresh, QNargs=QNargs, normalize=normalize) elif opt == "greedy": for iterm in xrange(1, len(propagation_c)): MPSnew = mpslib.add(MPSnew, scaletermlist[iterm], QNargs=QNargs) MPSnew = mpslib.canonicalise(MPSnew, 'r', QNargs=QNargs) MPSnew = mpslib.compress(MPSnew, 'r', trunc=thresh, QNargs=QNargs, normalize=normalize) else: if swap == False: MPSnew = mpslib.contract(approxeiHt, MPS, 'r', thresh, compress_method=compress_method, QNargs=QNargs) else: MPSnew = mpslib.contract(MPS, approxeiHt, 'r', thresh, compress_method=compress_method, QNargs=QNargs) if (cleanexciton is not None) and (QNargs is None): # clean the MPS according to quantum number constrain MPSnew = MPSsolver.clean_MPS('R', MPSnew, ephtable, cleanexciton) # compress the clean MPS MPSnew = mpslib.compress(MPSnew, 'r', trunc=thresh) if QNargs is None: print "tMPS dim:", [mps.shape[0] for mps in MPSnew] + [1] else: print "tMPS dim:", [mps.shape[0] for mps in MPSnew[0]] + [1] elif scheme == "TDVP_PS": # TDVP projector splitting MPSnew = [] # make sure the input MPS is L-orthogonal # in the spectrum calculation set compress_method = "variational" MPS = mpslib.canonicalise(MPS, "l") nMPS = len(MPS) # construct the environment matrix if mpompsmat.Enviro_check("L", range(nMPS - 1), prefix=prefix) == False: print "check_Enviro False" mpompsmat.construct_enviro(MPS, mpslib.conj(MPS), MPO, "L", prefix=prefix) MPSold = copy.deepcopy(MPS) # initial matrix ltensor = np.ones((1, 1, 1)) rtensor = np.ones((1, 1, 1)) loop = [['R', i] for i in xrange(nMPS - 1, -1, -1)] + [['L', i] for i in xrange(0, nMPS)] for system, imps in loop: if system == "R": lmethod, rmethod = "Enviro", "System" ltensor = mpompsmat.GetLR('L', imps-1, MPS, mpslib.conj(MPS), MPO, \ itensor=ltensor, method=lmethod, prefix=prefix) else: lmethod, rmethod = "System", "Enviro" rtensor = mpompsmat.GetLR('R', imps+1, MPS, mpslib.conj(MPS), MPO, \ itensor=rtensor, method=rmethod, prefix=prefix) def hop(mps): #S-a l-S # d #O-b-O-f-O # e #S-c k-S if mps.ndim == 3: path = [([0, 1],"abc, cek -> abek"),\ ([2, 0],"abek, bdef -> akdf"),\ ([1, 0],"akdf, lfk -> adl")] HC = tensorlib.multi_tensor_contract( path, ltensor, mps, MPO[imps], rtensor) #S-a l-S # d #O-b-O-f-O # e #S-c k-S # g elif mps.ndim == 4: path = [([0, 1],"abc, bdef -> acdef"),\ ([2, 0],"acdef, cegk -> adfgk"),\ ([1, 0],"adfgk, lfk -> adgl")] HC = tensorlib.multi_tensor_contract( path, ltensor, MPO[imps], mps, rtensor) return HC def hop_svt(mps): #S-a l-S # #O-b - b-O # #S-c k-S path = [([0, 1],"abc, ck -> abk"),\ ([1, 0],"abk, lbk -> al")] HC = tensorlib.multi_tensor_contract(path, ltensor, mps, rtensor) return HC shape = list(MPS[imps].shape) def func(t, y): return hop(y.reshape(shape)).ravel() / 1.0j sol = scipy.integrate.solve_ivp(func, (0, dt / 2.), MPS[imps].ravel(), method="RK45") print "nsteps for MPS[imps]:", len(sol.t) mps_t = sol.y[:, -1].reshape(shape) if system == "L" and imps != len(MPS) - 1: # updated imps site u, vt = scipy.linalg.qr(mps_t.reshape(-1, shape[-1]), mode="economic") MPS[imps] = u.reshape(shape[:-1] + [-1]) ltensor = mpompsmat.GetLR('L', imps, MPS, mpslib.conj(MPS), MPO, \ itensor=ltensor, method="System",prefix=prefix) # reverse update svt site shape_svt = vt.shape def func_svt(t, y): return hop_svt(y.reshape(shape_svt)).ravel() / 1.0j sol_svt = scipy.integrate.solve_ivp(func_svt, (0, -dt / 2), vt.ravel(), method="RK45") print "nsteps for svt:", len(sol_svt.t) MPS[imps + 1] = np.tensordot(sol_svt.y[:, -1].reshape(shape_svt), MPS[imps + 1], axes=(1, 0)) elif system == "R" and imps != 0: # updated imps site u, vt = scipy.linalg.rq(mps_t.reshape(shape[0], -1), mode="economic") MPS[imps] = vt.reshape([-1] + shape[1:]) rtensor = mpompsmat.GetLR('R', imps, MPS, mpslib.conj(MPS), MPO, \ itensor=rtensor, method="System", prefix=prefix) # reverse update u site shape_u = u.shape def func_u(t, y): return hop_svt(y.reshape(shape_u)).ravel() / 1.0j sol_u = scipy.integrate.solve_ivp(func_u, (0, -dt / 2), u.ravel(), method="RK45") print "nsteps for u:", len(sol_u.t) MPS[imps - 1] = np.tensordot(MPS[imps - 1], sol_u.y[:, -1].reshape(shape_u), axes=(-1, 0)) else: MPS[imps] = mps_t MPSnew = MPS if MPSnew[0].ndim == 3: # normalize norm = mpslib.norm(MPSnew) print "norm", norm MPSnew = mpslib.scale(MPSnew, 1. / norm) print "tMPS dim:", [mps.shape[0] for mps in MPSnew] + [1] elif scheme == "TDVP_MCTDH": # TDVP for original MCTDH MPSnew = [] if mpslib.is_left_canonical(MPS) == False: print "MPS is not left canonical!" MPS = mpslib.canonicalise(MPS, "l") # TODO, reuse the last step environment, L-R, R-L # construct the environment matrix mpompsmat.construct_enviro(MPS, mpslib.conj(MPS), MPO, "R") # initial matrix ltensor = np.ones((1, 1, 1)) rtensor = np.ones((1, 1, 1)) for imps in range(len(MPS)): ltensor = mpompsmat.GetLR('L', imps-1, MPS, mpslib.conj(MPS), MPO, \ itensor=ltensor, method="System") rtensor = mpompsmat.GetLR('R', imps+1, MPS, mpslib.conj(MPS), MPO, \ itensor=rtensor, method="Enviro") # density matrix S = mpslib.transferMat(MPS, mpslib.conj(MPS), "R", imps + 1) epsilon = 1e-10 w, u = scipy.linalg.eigh(S) w = w + epsilon * np.exp(-w / epsilon) print "sum w=", np.sum(w) #S = u.dot(np.diag(w)).dot(np.conj(u.T)) S_inv = u.dot(np.diag(1. / w)).dot(np.conj(u.T)) # pseudo inverse #S_inv = scipy.linalg.pinvh(S,rcond=1e-2) def projector(mps): # projector proj = np.tensordot(mps, np.conj(mps), axes=(2, 2)) Iden = np.diag(np.ones(np.prod(proj.shape[:2]))).reshape( proj.shape) proj = Iden - proj return proj def hop(mps): #S-a l-S # d #O-b-O-f-O # e #S-c k-S if mps.ndim == 3: path = [([0, 1],"abc, cek -> abek"),\ ([2, 0],"abek, bdef -> akdf"),\ ([1, 0],"akdf, lfk -> adl")] HC = tensorlib.multi_tensor_contract( path, ltensor, mps, MPO[imps], rtensor) #S-a l-S # d #O-b-O-f-O # e #S-c k-S # g elif mps.ndim == 4: path = [([0, 1],"abc, bdef -> acdef"),\ ([2, 0],"acdef, cegk -> adfgk"),\ ([1, 0],"adfgk, lfk -> adgl")] HC = tensorlib.multi_tensor_contract( path, ltensor, MPO[imps], mps, rtensor) return HC shape = MPS[imps].shape def func(t, y): y0 = y.reshape(shape) HC = hop(y0) if imps != len(MPS) - 1: proj = projector(y0) if y0.ndim == 3: HC = np.tensordot(proj, HC, axes=([2, 3], [0, 1])) HC = np.tensordot(proj, HC, axes=([2, 3], [0, 1])) elif y0.ndim == 4: HC = np.tensordot(proj, HC, axes=([3, 4, 5], [0, 1, 2])) HC = np.tensordot(proj, HC, axes=([3, 4, 5], [0, 1, 2])) return np.tensordot(HC, S_inv, axes=(-1, 0)).ravel() / 1.0j sol = scipy.integrate.solve_ivp(func, (0, dt), MPS[imps].ravel(), method="RK45") print "CMF steps:", len(sol.t) MPSnew.append(sol.y[:, -1].reshape(shape)) print "orthogonal1", np.allclose( np.tensordot(MPSnew[imps], np.conj(MPSnew[imps]), axes=([0, 1], [0, 1])), np.diag(np.ones(MPSnew[imps].shape[2]))) norm = mpslib.norm(MPSnew) MPSnew = mpslib.scale(MPSnew, 1. / norm) print "norm", norm print "tMPS dim:", [mps.shape[0] for mps in MPSnew] + [1] elif scheme == "TDVP_MCTDHnew": # new regularization scheme # JCP 148, 124105 (2018) # JCP 149, 044119 (2018) MPSnew = [] if mpslib.is_right_canonical(MPS) == False: print "MPS is not left canonical!" MPS = mpslib.canonicalise(MPS, "r") # construct the environment matrix mpompsmat.construct_enviro(MPS, mpslib.conj(MPS), MPO, "R") # initial matrix ltensor = np.ones((1, 1, 1)) rtensor = np.ones((1, 1, 1)) for imps in range(len(MPS)): shape = list(MPS[imps].shape) u, s, vt = scipy.linalg.svd(MPS[imps].reshape(-1, shape[-1]), full_matrices=False) MPS[imps] = u.reshape(shape[:-1] + [-1]) ltensor = mpompsmat.GetLR('L', imps-1, MPS, mpslib.conj(MPS), MPO, \ itensor=ltensor, method="System") rtensor = mpompsmat.GetLR('R', imps+1, MPS, mpslib.conj(MPS), MPO, \ itensor=rtensor, method="Enviro") epsilon = 1e-10 epsilon = np.sqrt(epsilon) s = s + epsilon * np.exp(-s / epsilon) svt = np.diag(s).dot(vt) rtensor = np.tensordot(rtensor, svt, axes=(2, 1)) rtensor = np.tensordot(np.conj(vt), rtensor, axes=(1, 0)) if imps != len(MPS) - 1: MPS[imps + 1] = np.tensordot(svt, MPS[imps + 1], axes=(-1, 0)) # density matrix S = s * s print "sum density matrix", np.sum(S) S_inv = np.diag(1. / s) def projector(mps): # projector proj = np.tensordot(mps, np.conj(mps), axes=(-1, -1)) Iden = np.diag(np.ones(np.prod(mps.shape[:-1]))).reshape( proj.shape) proj = Iden - proj return proj def hop(mps): #S-a l-S # d #O-b-O-f-O # e #S-c k-S if mps.ndim == 3: path = [([0, 1],"abc, cek -> abek"),\ ([2, 0],"abek, bdef -> akdf"),\ ([1, 0],"akdf, lfk -> adl")] HC = tensorlib.multi_tensor_contract( path, ltensor, mps, MPO[imps], rtensor) #S-a l-S # d #O-b-O-f-O # e #S-c k-S # g elif mps.ndim == 4: path = [([0, 1],"abc, bdef -> acdef"),\ ([2, 0],"acdef, cegk -> adfgk"),\ ([1, 0],"adfgk, lfk -> adgl")] HC = tensorlib.multi_tensor_contract( path, ltensor, MPO[imps], mps, rtensor) return HC shape = MPS[imps].shape def func(t, y): y0 = y.reshape(shape) HC = hop(y0) if imps != len(MPS) - 1: proj = projector(y0) if y0.ndim == 3: HC = np.tensordot(proj, HC, axes=([2, 3], [0, 1])) HC = np.tensordot(proj, HC, axes=([2, 3], [0, 1])) elif y0.ndim == 4: HC = np.tensordot(proj, HC, axes=([3, 4, 5], [0, 1, 2])) HC = np.tensordot(proj, HC, axes=([3, 4, 5], [0, 1, 2])) return np.tensordot(HC, S_inv, axes=(-1, 0)).ravel() / 1.0j sol = scipy.integrate.solve_ivp(func, (0, dt), MPS[imps].ravel(), method="RK45") print "CMF steps:", len(sol.t) mps = sol.y[:, -1].reshape(shape) if imps == len(MPS) - 1: print "s0", imps, s[0] MPSnew.append(mps * s[0]) else: MPSnew.append(mps) #print "orthogonal1", np.allclose(np.tensordot(MPSnew[imps], # np.conj(MPSnew[imps]), axes=([0,1],[0,1])), # np.diag(np.ones(MPSnew[imps].shape[2]))) if MPSnew[0].ndim == 3: norm = mpslib.norm(MPSnew) MPSnew = mpslib.scale(MPSnew, 1. / norm) print "norm", norm print "tMPS dim:", [mps.shape[0] for mps in MPSnew] + [1] return MPSnew
def ZeroTCorr(iMPS, HMPO, dipoleMPO, nsteps, dt, ephtable, thresh=0, \ cleanexciton=None, algorithm=1, prop_method="C_RK4",\ compress_method="svd", QNargs=None, approxeiHt=None, scheme="P&C"): ''' the bra part e^iEt is negected to reduce the oscillation algorithm: algorithm 1 is the only propagte ket in 0, dt, 2dt algorithm 2 is propagte bra and ket in 0, dt, 2dt (in principle, with same calculation cost, more accurate, because the bra is also entangled, the entanglement is not only in ket) compress_method: svd or variational cleanexciton: every time step propagation clean the good quantum number to discard the numerical error thresh: the svd threshold in svd or variational compress ''' AketMPS = mpslib.mapply(dipoleMPO, iMPS, QNargs=QNargs) # store the factor and normalize the AketMPS, factor is the length of AketMPS factor = mpslib.dot(mpslib.conj(AketMPS, QNargs=QNargs), AketMPS, QNargs=QNargs) factor = np.sqrt(np.absolute(factor)) print "factor", factor AketMPS = mpslib.scale(AketMPS, 1. / factor, QNargs=QNargs) if compress_method == "variational": AketMPS = mpslib.canonicalise(AketMPS, 'l', QNargs=QNargs) AbraMPS = mpslib.add(AketMPS, None, QNargs=QNargs) autocorr = [] t = 0.0 tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) if approxeiHt is not None: approxeiHpt = ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) approxeiHmt = ApproxPropagatorMPO(HMPO, -dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) else: approxeiHpt = None approxeiHmt = None for istep in xrange(nsteps): if istep != 0: t += dt if algorithm == 1: AketMPS = tMPS(AketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHpt, normalize=1., \ scheme=scheme, prefix=scheme) if algorithm == 2: if istep % 2 == 1: AketMPS = tMPS(AketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, QNargs=QNargs,\ approxeiHt=approxeiHpt, normalize=1., scheme=scheme, \ prefix=scheme+"1") else: AbraMPS = tMPS(AbraMPS, HMPO, -dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, QNargs=QNargs,\ approxeiHt=approxeiHmt, normalize=1., scheme=scheme,\ prefix=scheme+"2") ft = mpslib.dot(mpslib.conj(AbraMPS, QNargs=QNargs), AketMPS, QNargs=QNargs) * factor**2 wfn_store(AbraMPS, istep, str(dt) + str(thresh) + "AbraMPS.pkl") wfn_store(AketMPS, istep, str(dt) + str(thresh) + "AketMPS.pkl") autocorr.append(ft) autocorr_store(autocorr, istep) return autocorr
def Exact_Spectra(spectratype, mol, pbond, iMPS, dipoleMPO, nsteps, dt,\ temperature, GSshift=0.0, EXshift=0.0): ''' 0T emission spectra exact propagator the bra part e^iEt is negected to reduce the osillation and for single molecule, the EX space propagator e^iHt is local, and so exact GS/EXshift is the ground/excited state space energy shift the aim is to reduce the oscillation of the correlation fucntion support: all cases: 0Temi 1mol case: 0Temi, TTemi, 0Tabs, TTabs ''' assert spectratype in ["emi", "abs"] if spectratype == "emi": space1 = "EX" space2 = "GS" shift1 = EXshift shift2 = GSshift if temperature != 0: assert len(mol) == 1 else: assert len(mol) == 1 space1 = "GS" space2 = "EX" shift1 = GSshift shift2 = EXshift if temperature != 0: beta = constant.T2beta(temperature) print "beta=", beta thermalMPO, thermalMPOdim = ExactPropagatorMPO(mol, pbond, -beta / 2.0, space=space1, shift=shift1) ketMPS = mpslib.mapply(thermalMPO, iMPS) Z = mpslib.dot(mpslib.conj(ketMPS), ketMPS) print "partition function Z(beta)/Z(0)", Z else: ketMPS = iMPS Z = 1.0 AketMPS = mpslib.mapply(dipoleMPO, ketMPS) if temperature != 0: braMPS = mpslib.add(ketMPS, None) else: AbraMPS = mpslib.add(AketMPS, None) t = 0.0 autocorr = [] propMPO1, propMPOdim1 = ExactPropagatorMPO(mol, pbond, -1.0j * dt, space=space1, shift=shift1) propMPO2, propMPOdim2 = ExactPropagatorMPO(mol, pbond, -1.0j * dt, space=space2, shift=shift2) # we can reconstruct the propagator each time if there is accumulated error for istep in xrange(nsteps): if istep != 0: AketMPS = mpslib.mapply(propMPO2, AketMPS) if temperature != 0: braMPS = mpslib.mapply(propMPO1, braMPS) if temperature != 0: AbraMPS = mpslib.mapply(dipoleMPO, braMPS) ft = mpslib.dot(mpslib.conj(AbraMPS), AketMPS) autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def Quasi_Boson_MPO(opera, nqb, trunc, base=2, C1=1.0, C2=1.0): ''' nqb : # of quasi boson sites opera : operator to be decomposed "b + b^\dagger" ''' assert opera in ["b + b^\dagger","b^\dagger b", "b", "b^\dagger", \ "C1(b + b^\dagger) + C2(b + b^\dagger)^2"] # the structure is [bra_highest_bit, ket_highest_bit,..., bra_lowest_bit, # ket_lowest_bit] mat = np.zeros([ base, ] * nqb * 2) if opera == "b + b^\dagger" or opera == "b^\dagger" or opera == "b": if opera == "b + b^\dagger" or opera == "b^\dagger": for i in xrange(1, base**nqb): # b^+ lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array( map(int, baseConvert(i - 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = np.sqrt(i) if opera == "b + b^\dagger" or opera == "b": for i in xrange(0, base**nqb - 1): # b lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array( map(int, baseConvert(i + 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = np.sqrt(i + 1) elif opera == "C1(b + b^\dagger) + C2(b + b^\dagger)^2": # b^+ for i in xrange(1, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i - 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C1 * np.sqrt(i) # b for i in xrange(0, base**nqb - 1): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i + 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C1 * np.sqrt(i + 1) # bb for i in xrange(0, base**nqb - 2): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i + 2, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * np.sqrt(i + 2) * np.sqrt(i + 1) # b^\dagger b^\dagger for i in xrange(2, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i - 2, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * np.sqrt(i) * np.sqrt(i - 1) # b^\dagger b + b b^\dagger for i in xrange(0, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * float(i * 2 + 1) elif opera == "b^\dagger b": # actually Identity operator can be constructed directly for i in xrange(0, base**nqb): # I lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = float(i) # check the original mat # mat = np.moveaxis(mat,range(1,nqb*2,2),range(nqb,nqb*2)) # print mat.reshape(base**nqb,base**nqb) # decompose canonicalise MPO = [] mat = mat.reshape(1, -1) for idx in xrange(nqb - 1): U, S, Vt = scipy.linalg.svd(mat.reshape(mat.shape[0]*base**2,-1), \ full_matrices=False) U = U.reshape(mat.shape[0], base, base, -1) MPO.append(U) mat = np.einsum("i, ij -> ij", S, Vt) MPO.append(mat.reshape(-1, base, base, 1)) print "original MPO shape:", [i.shape[0] for i in MPO] + [1] # compress MPOnew = mpslib.compress(MPO, 'l', trunc=trunc) print "trunc", trunc, "distance", mpslib.distance(MPO, MPOnew) fidelity = mpslib.dot(mpslib.conj(MPOnew), MPO) / mpslib.dot( mpslib.conj(MPO), MPO) print "compression fidelity:: ", fidelity print "compressed MPO shape", [i.shape[0] for i in MPOnew] + [1] return MPOnew