def Hamiltonian(parameters, lattice): #Constructs the operators #(these are the essential operators that are needed for spin) si = qutip.qeye(2) sx = qutip.sigmax() #sy = qutip.sigmay() #sz = qutip.sigmaz() sp = qutip.sigmap() sm = qutip.sigmam() no = sp * sm #Constructs operators for the chain of length N #si_list = [] sx_list = [] #sy_list = [] #sz_list = [] #sp_list = [] #sm_list = [] no_list = [] #Runs over each site defining the operator on that site for k in range(lattice.numberOfSites): #Puts an indentity on every site op_list = [si] * lattice.numberOfSites #Defines the sigma_x on site k op_list[k] = sx sx_list.append(qutip.tensor(op_list)) #op_list[k] = sy #sy_list.append(qutip.tensor(op_list)) #op_list[k] = sz #sz_list.append(qutip.tensor(op_list)) #op_list[k] = sp #sp_list.append(qutip.tensor(op_list)) #op_list[k] = sm #sm_list.append(qutip.tensor(op_list)) op_list[k] = no no_list.append(qutip.tensor(op_list)) #Constructs the Hamiltonian H = 0 #Periodic boundary conditions #TODO define the periodic boundary conditions and closed in QJMCMath.neighbour operator with a choice for k in range(lattice.numberOfSites): H += (parameters.omega * (no_list[QJMCMath.neighbour(k, lattice.numberOfSites, -1)] + no_list[QJMCMath.neighbour(k, lattice.numberOfSites, 1)]) * sx_list[k]) #All objects must be in a scipy sparse format H = H.full() H = scipy.sparse.csc_matrix(H) return H
def approxFindDt(tStart, deltaT, HEffExponentDtSet, psi, r): t = tStart previousPsi = psi dt = 0 for i in range(1,len(HEffExponentDtSet)+1): psi = previousPsi t -= dt survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) dt = deltaT/(pow(10.0,i)) while survivialProbability>r: previousPsi = psi psi = HEffExponentDtSet[i-1].dot(psi) t += dt survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) return t, psi
def jumpBinary(tStart, psi, r, jumpOps, jumpOpsPaired, dtSet, HEffExponentDtSet): t = tStart startingIndex = 1 catchUpSet = [] while (tStart + dtSet[0] - t) > dtSet[-1]/2: #Extracts where the jump occured if (startingIndex != len(dtSet)): t, psi, catchUpSet = approxFindDtBinary(t, HEffExponentDtSet, dtSet, psi, r, startingIndex, catchUpSet) else: t, psi = QJMCEvolve.evolvePsiByExponent(psi, t, dtSet[-1], HEffExponentDtSet[-1]) #print(t) #print(catchUpSet) #Selects which jump occurs jumpSelect = jumpSelection(psi, jumpOpsPaired) #Performs the jump psi = jumpOps[jumpSelect].dot(psi) psi = QJMCMath.normalise(psi) #Performs catch-up t, psi, r, startingIndex, catchUpSet = catchUpApproxBinary(t, psi, dtSet, HEffExponentDtSet, catchUpSet) return t, psi, r
def measure(index, psi, eResults, eOps, histograms, savingSettings): #Extracts normalised wavefunctions psiNormalised = QJMCMath.normalise(psi) psiNormalisedLeft = numpy.conjugate(numpy.transpose(psiNormalised))[0] #Does the measurements: for i, result in enumerate(eResults): value = numpy.asscalar( numpy.real( numpy.dot(psiNormalisedLeft, (eOps[i].dot(psiNormalised))))) result[index] += value #Checks whether histograms are wanted if (savingSettings.histograms): #Goes through all histograms requested if (i < len(savingSettings.histogramOptions)): #Extracts the values for that histogram minimum = savingSettings.histogramOptions[i].minimum maximum = savingSettings.histogramOptions[i].maximum numberOfBars = savingSettings.histogramOptions[i].numberOfBars #Gets the position in the histogram position = int(((value - minimum) / maximum) * numberOfBars) #If the value lies outside of the range, places it on the edges if (position >= numberOfBars): position = numberOfBars - 1 elif (position < 0): position = 0 #Puts the count into the correct histogram histograms[i][index][position] += 1 #Advances the measurement by 1 index += 1 return index
def approxFindDt(tStart, deltaT, smallestDt, HEff, psi, r): t = tStart + deltaT previousPsi = psi dt = deltaT while dt > smallestDt: psi = previousPsi t -= dt survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) dt = dt / 10 #TODO this is not used but need to check why #HEffExponentDt = QJMCSetUp.HEffExponentProduction(HEff, dt) while survivialProbability > r: t += dt survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) return t, psi
def randomInitialState(H): dim = H.get_shape()[0] psi0 = numpy.ndarray(shape=(dim, 1), dtype=complex) for i in range(dim): r = random.random() u = random.random() psi0[i] = complex(r, u) psi0 = QJMCMath.normalise(psi0) return psi0
def jump(tStart, deltaT, psi, r, jumpOps, jumpOpsPaired, HEffExponentDtSet): #Extracts where the jump occured t, psi = approxFindDt(tStart, deltaT, HEffExponentDtSet, psi, r) #Selects which jump occurs jumpSelect = jumpSelection(psi, jumpOpsPaired) #Performs the jump psi = jumpOps[jumpSelect].dot(psi) psi = QJMCMath.normalise(psi) return t, psi
def approxFindDtBinary(t, HEffExponentDtSet, dtSet, psi, r, startingIndex, catchUpSet): previousPsi = psi #Does a binary search for the jump position for i in range(startingIndex,len(HEffExponentDtSet)-1): t, psi = QJMCEvolve.evolvePsiByExponent(psi, t, dtSet[i], HEffExponentDtSet[i]) survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) if survivialProbability>r: previousPsi = psi else: t -= dtSet[i] psi = previousPsi catchUpSet.append(i) #Does the final search which needs to correct for a +ve result t, psi = QJMCEvolve.evolvePsiByExponent(psi, t, dtSet[-1], HEffExponentDtSet[-1]) survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) if survivialProbability>r: t, psi = QJMCEvolve.evolvePsiByExponent(psi, t, dtSet[-1], HEffExponentDtSet[-1]) else: catchUpSet.append(len(HEffExponentDtSet)-1) return t, psi, catchUpSet
def catchUpApproxBinary(t, psi, dtSet, HEffExponentDtSet, catchUpSet): #Generates the random number for the new time selection r = random.random() catchUpReturn = catchUpSet for i in list(reversed(catchUpSet)): previousPsi = psi t, psi = QJMCEvolve.evolvePsiByExponent(psi, t, dtSet[i], HEffExponentDtSet[i]) catchUpReturn.remove(i) survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) if survivialProbability<r: return t - dtSet[i], previousPsi, r, i+1, catchUpReturn return t, psi, r, 0, catchUpReturn
def jump(tStart, deltaT, smallestDt, psi, r, jumpOps, jumpOpsPaired, HEff): #Extracts where the jump occured if deltaT > smallestDt: t, psi = approxFindDt(tStart, deltaT, smallestDt, HEff, psi, r) else: HEffExponentDt = HEffExponentProduction(HEff, deltaT) psi = HEffExponentDt.dot(psi) t = tStart + deltaT #Selects which jump occurs jumpSelect = QJMCJump.jumpSelection(psi, jumpOpsPaired) #Performs the jump psi = jumpOps[jumpSelect].dot(psi) psi = QJMCMath.normalise(psi) return t, psi
def test_randomInitialState(self): sx = qutip.sigmax() H = sx #All objects must be in a scipy sparse format H = H.full() H = scipy.sparse.csc_matrix(H) psi0 = [] num = 100 for i in range(num): psi0.append(QJMCSetUp.randomInitialState(H)) for i in range(num): self.assertAlmostEqual(1.0,QJMCMath.calculateSquareOfWavefunction(psi0[i])) for i in range(num - 1): for j in range(H.get_shape()[0]): self.assertNotAlmostEqual(psi0[i][j],psi0[i+1][j])
def catchUpApprox(t, tEnd, smallestDt, psi, jumpOps, jumpOpsPaired, HEff): #Generates the random number for the new time selection r = random.random() #TODO change this to a do a close check while (t < tEnd): #Evolves to the appropriate time dt = tEnd - t HEffExponentDt = QJMCSetUp.HEffExponentProduction(HEff, dt) previousPsi = psi psi = HEffExponentDt.dot(psi) #Progress the time t += dt #Checks if it has jumped survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) if survivialProbability < r: tStart = t - dt t, psi = jump(tStart, dt, smallestDt, previousPsi, r, jumpOps, jumpOpsPaired, HEff) r = random.random() return t, psi, r
def catchUpApprox(t, tEnd, deltaT, psi, jumpOps, jumpOpsPaired,HEffExponentDtSet): #Generates the random number for the new time selection r = random.random() for i in range(1,len(HEffExponentDtSet)+1): #Start the change in time at the largest first and then get smaller dt = deltaT/(pow(10.0,i)) while ((tEnd - t) > dt): #Save the previous wave function prev = psi #Evolve it psi = HEffExponentDtSet[i-1].dot(psi) #Progress the time t += dt #Check if it has jumped survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) if survivialProbability<r: #Peform the jump in the last time step tStart = t - dt t, psi = jump(tStart, deltaT, prev, r, jumpOps, jumpOpsPaired, HEffExponentDtSet) #Produce a new random number for time selection r = random.random() return t, psi, r
def QJMCRun(settings, savingSettings, H, jumpOps, eOps, psi0): #Tests the inputs QJMCSetUp.dimensionTest(H, jumpOps, eOps, psi0) QJMCSetUp.typeTest(settings, savingSettings, H, jumpOps, eOps, psi0) startTime = time.time() #Creates the time array tList = numpy.linspace(0, settings.T, settings.numberOfPoints) #Gets the pairs of jump operators for later use jumpOpsPaired = QJMCSetUp.jumpOperatorsPaired(jumpOps) #Produces expectation operators squared to help produce variance QJMCSetUp.addExpectationSquared(eOps) #Produces results arrays eResults = QJMCSetUp.eResultsProduction(eOps, settings.numberOfPoints) #Produces the histograms list if (savingSettings.histograms): histograms = QJMCSetUp.histogramProduction( savingSettings.histogramOptions, settings.numberOfPoints) else: histograms = [] #Produces the effective hamiltonain as an exponent and gets the smaller set HEffExponentDtSet, dtSet = QJMCSetUp.HEffExponentSetProductionBinary( H, jumpOpsPaired, tList[1], settings) #Used to track the progress of the simulation bar = progressbar.ProgressBar(maxval=settings.numberOfTrajectories, \ widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()]) bar.start() for traj in range(settings.numberOfTrajectories): bar.update(traj) #Resets the system #Selects a random initial state if requested if settings.randomInitialStates: psi0 = QJMCSetUp.randomInitialState(H) psi = psi0 previousPsi = psi index = 0 #Performs the first measure at t=0 index = QJMCMeasure.measure(index, psi, eResults, eOps, histograms, savingSettings) #Selects the random number for the first time selection r = random.random() #START OF LOOP while (index < settings.numberOfPoints): #Saves the previous state if necessary previousPsi = psi #Progresses to the next time step psi = HEffExponentDtSet[0].dot(psi) #Calculates the survivial probability survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) #Checks if it has jumped in the last time step if survivialProbability < r: #Performs the jump at the more accurate time _, psi, r = QJMCJump.jumpBinary(tList[index - 1], previousPsi, r, jumpOps, jumpOpsPaired, dtSet, HEffExponentDtSet) #Performs the measurement index = QJMCMeasure.measure(index, psi, eResults, eOps, histograms, savingSettings) bar.update(settings.numberOfTrajectories) print('Saving') #Averages all the results eResults = QJMCMeasure.averageResults(eResults, settings) if (savingSettings.histograms): histograms = QJMCMeasure.averageHistograms( histograms, settings.numberOfTrajectories) #Saves the results QJMCMeasure.saveResults(settings, savingSettings, eResults) if (savingSettings.histograms): QJMCMeasure.saveHistograms(settings, savingSettings, histograms) endTime = time.time() print('Time taken ' + str(timedelta(seconds=endTime - startTime)))
def QJMCRunLowMemory(settings, savingSettings, tList, H, jumpOps, eOps, psi0): #Tests the inputs QJMCSetUp.dimensionTest(H, jumpOps, eOps, psi0) #TODO add type test on tList QJMCSetUp.typeTest(settings, savingSettings, H, jumpOps, eOps, psi0) startTime = time.time() #Sets the number of points based on the tList #TODO check this works correctly settings.numberOfPoints = len(tList) #Gets the pairs of jump operators for later use jumpOpsPaired = QJMCSetUp.jumpOperatorsPaired(jumpOps) #Gets the effective Hamiltonian HEff = QJMCSetUp.HEffProduction(H, jumpOpsPaired) #Produces expectation operators squared to help produce variance QJMCSetUp.addExpectationSquared(eOps) #Produces results arrays eResults = QJMCSetUp.eResultsProduction(eOps, settings.numberOfPoints) #Produces the histograms if (savingSettings.histograms): histograms = QJMCSetUp.histogramProduction( savingSettings.histogramOptions, settings.numberOfPoints) #Used to track the progress of the simulation bar = progressbar.ProgressBar(maxval=settings.numberOfTrajectories, \ widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()]) bar.start() for traj in range(settings.numberOfTrajectories): bar.update(traj) #Resets the system #Selects a random initial state if requested if settings.randomInitialStates: psi0 = QJMCSetUp.randomInitialState(H) psi = psi0 t = 0 index = 0 #Performs the first measure at t=0 index = QJMCMeasure.measure(index, psi, eResults, eOps, histograms, savingSettings) #Selects the random number for the first time selection r = random.random() #START OF LOOP while (index < settings.numberOfPoints): #Progresses to the next time step dt = tList[index] - tList[index - 1] t, psi = QJMCEvolve.evolvePsi(psi, t, dt, HEff) #Calculates the survivial probability survivialProbability = QJMCMath.calculateSquareOfWavefunction(psi) #Checks if it has jumped in the last time step if survivialProbability < r: #Performs the jump at the more accurate time t, psi = QJMCJumpLowMemory.jump(tList[index - 1], dt, settings.smallestDt, psi, r, jumpOps, jumpOpsPaired, HEff) #Catches up the accurate time to the index time, performing any #other jumps t, psi, r = QJMCJumpLowMemory.catchUpApprox( t, tList[index], settings.smallestDt, psi, jumpOps, jumpOpsPaired, HEff) #Performs the measurement index = QJMCMeasure.measure(index, psi, eResults, eOps, histograms, savingSettings) bar.update(settings.numberOfTrajectories) print('Saving') #Averages all the results eResults = QJMCMeasure.averageResults(eResults, settings) if (savingSettings.histograms): histograms = QJMCMeasure.averageHistograms( histograms, settings.numberOfTrajectories) #Saves the results QJMCMeasure.saveResults(settings, savingSettings, eResults) if (savingSettings.histograms): QJMCMeasure.saveHistograms(settings, savingSettings, histograms) endTime = time.time() print('Time taken ' + str(timedelta(seconds=endTime - startTime)))
def jumpOperators(parameters, lattice): #Constructs the operators si = qutip.qeye(2) #sx = qutip.sigmax() #sy = qutip.sigmay() #sz = qutip.sigmaz() sp = qutip.sigmap() sm = qutip.sigmam() no = sp * sm #print no #Constructs operators for the chain of length N #si_list = [] #sx_list = [] #sy_list = [] #sz_list = [] sp_list = [] sm_list = [] no_list = [] #si_list.append(qutip.tensor([si] * N)) for k in range(lattice.numberOfSites): op_list = [si] * lattice.numberOfSites #op_list[k] = sx #sx_list.append(qutip.tensor(op_list)) #op_list[k] = sy #sy_list.append(qutip.tensor(op_list)) #op_list[k] = sz #sz_list.append(qutip.tensor(op_list)) op_list[k] = sp sp_list.append(qutip.tensor(op_list)) op_list[k] = sm sm_list.append(qutip.tensor(op_list)) op_list[k] = no no_list.append(qutip.tensor(op_list)) #Collapse operators c_op_list = [] #Flips if parameters.kappa > 0: #Flip down check right for k in range(lattice.numberOfSites): c_op_list.append( np.sqrt(parameters.kappa) * sm_list[k] * no_list[QJMCMath.neighbour(k, lattice.numberOfSites, 1)]) #Flip down check left for k in range(lattice.numberOfSites): c_op_list.append( np.sqrt(parameters.kappa) * sm_list[k] * no_list[QJMCMath.neighbour(k, lattice.numberOfSites, -1)]) #Flip up check right for k in range(lattice.numberOfSites): c_op_list.append( np.sqrt(parameters.kappa) * sp_list[k] * no_list[QJMCMath.neighbour(k, lattice.numberOfSites, 1)]) #Flip up check left for k in range(lattice.numberOfSites): c_op_list.append( np.sqrt(parameters.kappa) * sp_list[k] * no_list[QJMCMath.neighbour(k, lattice.numberOfSites, -1)]) #Decay (the greater than 0 prevents the production of empty jump opertors) if parameters.gamma > 0: for k in range(lattice.numberOfSites): c_op_list.append(np.sqrt(parameters.gamma) * sm_list[k]) #Converts the existing arrays into sparse arrays for i, cOp in enumerate(c_op_list): #print i c_op_list[i] = cOp.full() c_op_list[i] = scipy.sparse.csc_matrix(c_op_list[i]) return c_op_list