示例#1
0
    def compute_tv_mixing(self,
                          indices=None,
                          convergence_tol=0.05,
                          refinement_tol=0.1):
        """ Compute the mixing in total variation for a number of 
		distributions. 

		Automatically iterates the distributions to stationarity if necessary.

		indices: list containing indices of distributions for which to find the
		total variation mixing. Defaults to None (for all distributions).
		convergence_tol: tolerance in total variation distance for the determination of convergence.
		Defaults to 0.05. 
		refinement_tol: maximum distance in total variation between two iterations. If the 
		mixing is plotted, this corresponds to the smoothness of the graph. Defaults to 0.1.

		Returns nothing.
		"""
        if indices == None:
            indices = range(self.num_distributions())

        self.iterate_distributions_to_stationarity(indices,
                                                   tv_tol=convergence_tol)

        # want subsequent iterations to have a maximal difference of refinement_tol units
        # of total variation (as compared to the stationary distribution)
        self.refine_iterations(
            indices, lambda t1, x1, t2, x2: abs(
                mkm.total_variation(x1, self.get_stationary()) - mkm.
                total_variation(x2, self.get_stationary())) > refinement_tol)
示例#2
0
	def distribution_tv_mixing(self,index):
		if self.sd == None:
			raise Exception('cant determinde the mixing as long as the stationary distribution is unknown')

		x = []
		tv = []
		
		for idx,t in enumerate(self.get_iteration_times(index)):
			x.append(t)
			tv.append(mkm.total_variation(self.sd,self.get_iteration(index,t)))

		return (x,tv)
示例#3
0
    def iterate_distributions(self, indices, k, tv_tol=0.05):
        """ Iterate a number of distributions k steps from their last iteration.

		This is the core method for iterating distributions to stationarity.

		If the number of distributions is >= 3, it will automatically 
		set the stationary distribution, if unknown and found.

		indices: list containing indices of distributions to be iterated
		k: number of iterations to perform
		"""
        x = []
        for i in indices:
            x.append(self.get_last_iteration(i))

        # invoke the external method performing the iteration
        y = mkm.iterate_distributions(self.p, numpy.array(x), k)

        for idx, val in enumerate(indices):
            self.add_iteration(val,
                               self.last_iteration_time(val) + k, y[idx, :])

        # check if we found the stationary distribution
        if len(indices) >= 3:
            # first check the definition of stationarity for all iterations
            for i in indices:
                last = self.get_last_iteration(i)
                last_iterated = mkm.iterate_distributions(self.p, last, 100)

                # is 1e-6 a good threshold? (however this can never be trusted -> cutoff)
                if mkm.relative_error(last, last_iterated) > 1e-6:
                    return

            # check pairwise distance <= tol
            for i in indices:
                d_i = self.get_last_iteration(i)

                for j in indices:
                    d_j = self.get_last_iteration(j)

                    if mkm.total_variation(d_i, d_j) > tv_tol:
                        return

            # take the arithmetic mean of all iterations as the stationary distribution
            stationary_candidate = numpy.zeros(self.n)

            for i in indices:
                stationary_candidate = stationary_candidate + self.get_last_iteration(
                    i)

            stationary_candidate = stationary_candidate / len(indices)

            self.set_stationary(stationary_candidate)
示例#4
0
    def close_to_stationarity(self, dist, tv_tol=0.05):
        """ For a distribution dist, determine if it is "close"
		to the stationary distribution.

		Currently implemented as total variation distance < tv_tol.

		tv_tol: Desired tolerance in total variation. Defaults to 0.05.
		"""
        if self.sd == None:
            return False

        if mkm.total_variation(dist, self.sd) < tv_tol:
            return True
示例#5
0
	def close_to_stationarity(self,dist,tv_tol=0.05):
		""" For a distribution dist, determine if it is "close"
		to the stationary distribution.

		Currently implemented as total variation distance < tv_tol.

		tv_tol: Desired tolerance in total variation. Defaults to 0.05.
		"""
		if self.sd == None:
			return False

		if mkm.total_variation(dist,self.sd) < tv_tol:
			return True
示例#6
0
    def convergence_video(self, path, index, seconds):
        """
		"""
        import matplotlib.pyplot as plt

        nframes = 100 * seconds

        # first iterate the distribution to stationarity (if that has not been done already)
        self.iterate_distributions_to_stationarity([index])

        # we want the video to end once the stationary distribution is reached
        t_end = self.last_iteration_time(index)

        for t in self.get_iteration_times(index):
            if mkm.total_variation(self.get_iteration(index, t),
                                   self.get_stationary()) < 0.01:
                t_end = int(t * 1.05)
                break

        frametime = t_end / float(nframes)

        # if possible, we want an iteration for every frame
        self.refine_iterations(
            [index], lambda t1, x1, t2, x2:
            (t1 <= t_end or t2 <= t_end) and abs(t1 - t2) > frametime)

        def frame(i):
            fig = plt.figure(figsize=(19.20, 10.80), dpi=100)

            # time of closest iteration
            t = self.closest_iteration_time(index, i * frametime)

            iteration = self.get_iteration(index, t)
            mkm.pyplot_bar(iteration)

            plt.title("Probability distribution after %d steps" % (t))
            plt.xlabel("Markov chain state space")
            plt.ylabel("Probabiliy")

            plt.tick_params(axis='x',
                            which='both',
                            bottom='off',
                            top='off',
                            labelbottom='off')

            plt.xlim(0, self.n)
            plt.ylim(0, 1.1 * numpy.max(iteration))

            return fig

        mkm.matplotlib_plots_to_video(path, frame, nframes)
示例#7
0
	def iterate_distributions(self,indices,k,tv_tol=0.05):
		""" Iterate a number of distributions k steps from their last iteration.

		This is the core method for iterating distributions to stationarity.

		If the number of distributions is >= 3, it will automatically 
		set the stationary distribution, if unknown and found.

		indices: list containing indices of distributions to be iterated
		k: number of iterations to perform
		"""
		x = []
		for i in indices:
			x.append(self.get_last_iteration(i))

		# invoke the external method performing the iteration
		y = mkm.iterate_distributions(self.p,numpy.array(x),k)

		for idx, val in enumerate(indices):
			self.add_iteration(val,self.last_iteration_time(val)+k,y[idx,:])

		# check if we found the stationary distribution
		if len(indices) >= 3:
			# first check the definition of stationarity for all iterations
			for i in indices:
				last = self.get_last_iteration(i)
				last_iterated = mkm.iterate_distributions(self.p,last,100)
						
				# is 1e-6 a good threshold? (however this can never be trusted -> cutoff)
				if mkm.relative_error(last,last_iterated) > 1e-6:
					return

			# check pairwise distance <= tol
			for i in indices:
				d_i = self.get_last_iteration(i)

				for j in indices:
					d_j = self.get_last_iteration(j)

					if mkm.total_variation(d_i, d_j) > tv_tol:
						return

			# take the arithmetic mean of all iterations as the stationary distribution
			stationary_candidate = numpy.zeros(self.n)

			for i in indices:
				stationary_candidate = stationary_candidate + self.get_last_iteration(i)

			stationary_candidate = stationary_candidate / len(indices)

			self.set_stationary(stationary_candidate)			
示例#8
0
	def distribution_tv_mixing(self,index):
		""" Returns a tupel (t,tv) that contains the distance in total variation
		to stationarity for the given distribution at all known times t.

		index: index of the distribution
		"""
		x = []
		tv = []
		
		for idx,t in enumerate(self.get_iteration_times(index)):
			x.append(t)
			tv.append(mkm.total_variation(self.sd,self.get_iteration(index,t)))

		return (x,tv)
示例#9
0
    def distribution_tv_mixing(self, index):
        """ Returns a tupel (t,tv) that contains the distance in total variation
		to stationarity for the given distribution at all known times t.

		index: index of the distribution
		"""
        x = []
        tv = []

        for idx, t in enumerate(self.get_iteration_times(index)):
            x.append(t)
            tv.append(
                mkm.total_variation(self.sd, self.get_iteration(index, t)))

        return (x, tv)
示例#10
0
	def convergence_video(self,path,index,seconds):
		"""
		"""
		import matplotlib.pyplot as plt

		nframes = 100*seconds

		# first iterate the distribution to stationarity (if that has not been done already)
		self.iterate_distributions_to_stationarity([index])

		# we want the video to end once the stationary distribution is reached
		t_end = self.last_iteration_time(index)

		for t in self.get_iteration_times(index):
			if mkm.total_variation(self.get_iteration(index,t), self.get_stationary()) < 0.01:
				t_end = int(t*1.05)
				break

		frametime = t_end/float(nframes)

		# if possible, we want an iteration for every frame
		self.refine_iterations([index], lambda t1,x1,t2,x2: (t1<=t_end or t2<=t_end) and abs(t1-t2) > frametime)

		def frame(i):
			fig = plt.figure(figsize=(19.20, 10.80), dpi=100)

			# time of closest iteration
			t = self.closest_iteration_time(index,i*frametime)

			iteration = self.get_iteration(index,t)
			mkm.pyplot_bar(iteration)
		
			plt.title("Probability distribution after %d steps" % (t))
			plt.xlabel("Markov chain state space")
			plt.ylabel("Probabiliy")

			plt.tick_params(axis='x', which='both', bottom='off', top='off', labelbottom='off')
		
			plt.xlim(0, self.n)
			plt.ylim(0, 1.1*numpy.max(iteration))

			return fig

		mkm.matplotlib_plots_to_video(path, frame, nframes)
示例#11
0
	def compute_tv_mixing(self,indices=None):
		""" Compute the mixing in total variation for a number of 
		distributions. 

		Automatically iterates the distributions to stationarity if necessary.

		indices: list containing indices of distributions for which to find the
		total variation mixing. Defaults to None (for all distributions).

		Returns nothing.
		"""
		if indices == None:
			indices = range(self.num_distributions()) 

		self.iterate_distributions_to_stationarity(indices)

		# want subsequent iterations to have a maximal difference of 0.1 units 
		# of total variation (as compared to the stationary distribution)		
		self.refine_iterations(indices, lambda x,y: abs(mkm.total_variation(x,self.get_stationary_distribution()) - mkm.total_variation(y,self.get_stationary_distribution())) > 0.1 )
示例#12
0
	def compute_tv_mixing(self,indices=None,convergence_tol=0.05,refinement_tol=0.1):
		""" Compute the mixing in total variation for a number of 
		distributions. 

		Automatically iterates the distributions to stationarity if necessary.

		indices: list containing indices of distributions for which to find the
		total variation mixing. Defaults to None (for all distributions).
		convergence_tol: tolerance in total variation distance for the determination of convergence.
		Defaults to 0.05. 
		refinement_tol: maximum distance in total variation between two iterations. If the 
		mixing is plotted, this corresponds to the smoothness of the graph. Defaults to 0.1.

		Returns nothing.
		"""
		if indices == None:
			indices = range(self.num_distributions()) 

		self.iterate_distributions_to_stationarity(indices, tv_tol=convergence_tol)

		# want subsequent iterations to have a maximal difference of refinement_tol units 
		# of total variation (as compared to the stationary distribution)		
		self.refine_iterations(indices, lambda t1,x1,t2,x2: abs(mkm.total_variation(x1,self.get_stationary()) - mkm.total_variation(x2,self.get_stationary())) > refinement_tol)
示例#13
0
    def plot_tv_mixing(self,
                       indices=None,
                       y_tol=0.1,
                       threshold=0.05,
                       text=True):
        """ Plots the total variation mixing for a given number
		of distributions.

		Iterates the distributions to stationarity if necessary.

		The x-limit of the plot will be choosen such that the total varation distance
		to stationarity of all distributions is below threshold.

		indices: list with indices of distributions for which to plot the 
		mixing. Can also be an integer, indicating a single distribution.
		Defaults to None (for all distributions).
		
		y_tol: maximum y-distance between to data points on the same graph

		threshold: determines the x-limit of the plot. Defaults to 0.05.

		text: if the plot should contain axis labels and a title
		
		"""
        import matplotlib.pyplot as plt

        if indices == None:
            indices = range(self.num_distributions())

        if isinstance(indices, int):
            indices = [indices]

        # iterate distributions to stationarity, given the desired threshold
        self.compute_tv_mixing(indices,
                               convergence_tol=threshold,
                               refinement_tol=y_tol)

        # determine the x-limit of the plot
        xlim = 5

        for index in indices:
            for t in self.get_iteration_times(index):
                if t > xlim and mkm.total_variation(
                        self.sd, self.get_iteration(index, t)) > threshold:
                    xlim = t

        self.assert_iteration(indices, xlim)
        self.compute_tv_mixing(indices,
                               convergence_tol=threshold,
                               refinement_tol=y_tol)  # need the refinement

        # plot
        for index in indices:
            x = []
            tv = []

            for t in self.get_iteration_times(index):
                if t > xlim:
                    continue
                x.append(t)
                tv.append(
                    mkm.total_variation(self.sd, self.get_iteration(index, t)))

            plt.plot(x, tv)

        plt.xlim(0, xlim)
        plt.ylim(0, 1)

        if text:
            plt.xlabel("t")
            plt.ylabel("Total variation distance to stationarity")

        plt.show()
示例#14
0
	def plot_tv_mixing(self,indices=None,y_tol=0.1,threshold=0.05,text=True):
		""" Plots the total variation mixing for a given number
		of distributions.

		Iterates the distributions to stationarity if necessary.

		The x-limit of the plot will be choosen such that the total varation distance
		to stationarity of all distributions is below threshold.

		indices: list with indices of distributions for which to plot the 
		mixing. Can also be an integer, indicating a single distribution.
		Defaults to None (for all distributions).
		
		y_tol: maximum y-distance between to data points on the same graph

		threshold: determines the x-limit of the plot. Defaults to 0.05.

		text: if the plot should contain axis labels and a title
		
		"""
		import matplotlib.pyplot as plt

		if indices == None:
			indices = range(self.num_distributions()) 

		if isinstance(indices, int):
			indices = [indices]

		# iterate distributions to stationarity, given the desired threshold
		self.compute_tv_mixing(indices, convergence_tol=threshold, refinement_tol=y_tol)

		# determine the x-limit of the plot
		xlim = 5

		for index in indices:
			for t in self.get_iteration_times(index):
				if t > xlim and mkm.total_variation(self.sd,self.get_iteration(index,t)) > threshold:
					xlim = t

		self.assert_iteration(indices, xlim)
		self.compute_tv_mixing(indices, convergence_tol=threshold, refinement_tol=y_tol) # need the refinement

		# plot
		for index in indices:
			x = []
			tv = []
					
			for t in self.get_iteration_times(index):
				if t > xlim:
					continue
				x.append(t)
				tv.append(mkm.total_variation(self.sd,self.get_iteration(index,t)))

			plt.plot(x, tv)

		plt.xlim(0, xlim)
		plt.ylim(0, 1)

		if text:
			plt.xlabel("t")
			plt.ylabel("Total variation distance to stationarity")

		plt.show()
示例#15
0
	def close_to_stationarity(self,dist):
		if self.sd == None:
			return False

		if mkm.total_variation(dist,self.sd) < 0.05:
			return True