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
예제 #5
0
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
예제 #10
0
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])
예제 #12
0
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
예제 #14
0
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)))
예제 #15
0
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