def get_mi_asymptotics(M, R): """ Return a multiline string with some asymptotics. @param M: pure mutation rate matrix @param R: mutation-selection balance rate matrix @return: multiline string """ out = StringIO() # get the stationary distributions M_v = mrate.R_to_distn(M) R_v = mrate.R_to_distn(R) # The shannon entropy of the stationary distribution of the process # determines the mutual information at small times. M_shannon_entropy = -np.dot(np.log(M_v), M_v) R_shannon_entropy = -np.dot(np.log(R_v), R_v) if not np.allclose(M_shannon_entropy, R_shannon_entropy): print >> out, 'At small enough times' if R_shannon_entropy < M_shannon_entropy: print >> out, '* pure mutation', else: print >> out, '* mutation-selection balance', print >> out, 'will be more informative' print >> out, 'because its stationary distribution has greater', print >> out, 'Shannon entropy.' else: print >> out, 'There is not enough difference between the' print >> out, 'Shannon entropies of the stationary distributions' print >> out, 'to determine which process' print >> out, 'is more informative at times near zero' print >> out # The spectral gap of the process # determines the mutual information at large times. M_spectral_gap = sorted(abs(w) for w in scipy.linalg.eigvals(M))[1] R_spectral_gap = sorted(abs(w) for w in scipy.linalg.eigvals(R))[1] M_cheeg_low, M_cheeg_mid, M_cheeg_high = cheeger.get_cheeger_bounds(M, M_v) R_cheeg_low, R_cheeg_mid, R_cheeg_high = cheeger.get_cheeger_bounds(R, R_v) if not np.allclose(M_spectral_gap, R_spectral_gap): print >> out, 'At large enough times' if R_spectral_gap < M_spectral_gap: print >> out, '* mutation-selection balance', else: print >> out, '* pure mutation', print >> out, 'will be more informative' print >> out, 'because it has a smaller spectral gap.' if (R_cheeg_high < M_cheeg_low) or (M_cheeg_high < R_cheeg_low): print >> out, 'And also because of the isoperimetric bounds.' else: print >> out, 'There is not enough difference between the' print >> out, 'spectral gaps to determine which process' print >> out, 'is more informative at times near infinity' print >> out # return the text return out.getvalue().strip()
def __init__(self, Q): """ @param Q: rate matrix """ # define intermediate variables v = mrate.R_to_distn(Q) n = len(v) psi = np.sqrt(v) c_low, c_mid, c_high = cheeger.get_cheeger_bounds(Q, v) # define member variables to summarize the rate matrix self.rate_matrix = Q self.exch_matrix = Q / v if not np.allclose(self.exch_matrix, self.exch_matrix.T): print self.exch_matrix raise ValueError('expected symmetry') self.sim_sym_matrix = np.outer(psi, 1 / psi) * Q if not np.allclose(self.sim_sym_matrix, self.sim_sym_matrix.T): print self.sim_sym_matrix raise ValueError('expected symmetry') self.distn = v self.distn_shannon_entropy = -ndot(np.log(v), v) self.distn_logical_entropy = ndot(v, 1 - v) self.expected_rate = -ndot(np.diag(Q), v) self.spectrum = scipy.linalg.eigvalsh(self.sim_sym_matrix) self.spectral_gap = -self.spectrum[-2] self.isoperimetric_low = c_low self.isoperimetric_constant = c_mid self.isoperimetric_high = c_high self.trace_bound_high = -sum(np.diag(Q)) / (n - 1)
def __init__(self, Q): """ @param Q: rate matrix """ # define intermediate variables v = mrate.R_to_distn(Q) n = len(v) psi = np.sqrt(v) c_low, c_mid, c_high = cheeger.get_cheeger_bounds(Q, v) # define member variables to summarize the rate matrix self.rate_matrix = Q self.exch_matrix = Q / v if not np.allclose(self.exch_matrix, self.exch_matrix.T): print self.exch_matrix raise ValueError('expected symmetry') self.sim_sym_matrix = np.outer(psi, 1/psi) * Q if not np.allclose(self.sim_sym_matrix, self.sim_sym_matrix.T): print self.sim_sym_matrix raise ValueError('expected symmetry') self.distn = v self.distn_shannon_entropy = -ndot(np.log(v), v) self.distn_logical_entropy = ndot(v, 1-v) self.expected_rate = -ndot(np.diag(Q), v) self.spectrum = scipy.linalg.eigvalsh(self.sim_sym_matrix) self.spectral_gap = -self.spectrum[-2] self.isoperimetric_low = c_low self.isoperimetric_constant = c_mid self.isoperimetric_high = c_high self.trace_bound_high = -sum(np.diag(Q)) / (n-1)