def epd(self, g__, pd_flag=False, debug_flag=False): w = -1 values = nx.get_node_attributes(g__, 'fv') simplices = [[x[0], x[1]] for x in list(g__.edges)] + [[x] for x in g__.nodes()] up_simplices = [ d.Simplex(s, max(values[v] for v in s)) for s in simplices ] down_simplices = [ d.Simplex(s + [w], min(values[v] for v in s)) for s in simplices ] if pd_flag == True: down_simplices = [] # mask the extended persistence here up_simplices.sort(key=lambda s1: (s1.dimension(), s1.data)) down_simplices.sort(reverse=True, key=lambda s: (s.dimension(), s.data)) f = d.Filtration([d.Simplex([w], -float('inf'))] + up_simplices + down_simplices) m = d.homology_persistence(f) dgms = d.init_diagrams(m, f) if debug_flag == True: print( 'Calling compute_EPD here with success. Print first dgm in dgms' ) print_dgm(dgms[0]) return dgms
def build_filtrations(self): ''' This method constructs a filtration given a cover and the data RETURNS ------- filtration {dionysus.Filtration} a filtration of simplicial complices ''' # Instantiate the filtration objects self.observer_filtration_ = d.Filtration() self.landmark_filtration_ = d.Filtration() # Set the end of the filtration to be the maximum visibility end = self.distances_.max() # Build iterative complexes and add simplices to filtration with the # visibility threshold they were born for p in np.linspace(0,end): observer_complex, landmark_complex = self.build_complex(p) for simplex in observer_complex: self.observer_filtration_.append(d.Simplex(simplex, p)) for simplex in landmark_complex: self.landmark_filtration_.append(d.Simplex(simplex, p)) # Sort the filtrations self.observer_filtration_.sort() self.landmark_filtration_.sort() return self.observer_filtration_, self.landmark_filtration_
def collect_result(res): nonlocal id nonlocal f nonlocal nm nonlocal wm for enum in res: nodes = enum[0] weight = enum[1][0] if len(nodes) == 1: if nodes[0] not in nm: nm[nodes[0]] = id id += 1 f.append(dion.Simplex([nm[nodes[0]]], weight)) else: f.append(dion.Simplex([nm[nodes[0]]], weight)) if len(nodes) == 2: act_weight = enum[1][1] if nodes[0] not in nm: nm[nodes[0]] = id id += 1 if nodes[1] not in nm: nm[nodes[1]] = id id += 1 wm[(nodes[0], nodes[1])] = act_weight f.append(dion.Simplex([nm[nodes[0]], nm[nodes[1]]], weight))
def linear_filtration_static(f, h1, fc, h1_births, id_start_1, id_start_2, percentile=None, last=False): h1 = h1.cpu().detach().numpy() mat = fc.weight.data.cpu().detach().numpy() h2_births = np.zeros(mat.shape[0]) if percentile is None: percentile_2 = 0 else: percentile_2 = np.percentile(mat, percentile) gtzh1 = np.argwhere(h1 > 0) for xi in gtzh1: all_xis = np.absolute(mat[:,xi]) max_xi = all_xis.max() if h1_births[xi] < max_xi: h1_births[xi] = max_xi gtpall_xis = np.argwhere(all_xis > percentile_2)[:,0] for mj in gtpall_xis: if h2_births[mj] < all_xis[mj]: h2_births[mj] = all_xis[mj] f.append(dion.Simplex([xi+id_start_1, mj+id_start_2], all_xis[mj])) # now add maximum birth time for each h1 hidden vertex to the filtration. for i in np.argwhere(h1_births > 0): f.append(dion.Simplex([i+id_start_1], h1_births[i])) # last linear layer in network, add final if last: for i in np.argwhere(h2_births > 0): f.append(dion.Simplex([i+id_start_2], h2_births[i])) return f return f, h2_births
def EPH_mask(vertex_values, simplices): s2v_lst = [[ sorted(s), sorted([[vertex_values[v], v] for v in s], key=lambda x: x[0]) ] for s in simplices] f_ord = [dionysus.Simplex(s[0], s[1][-1][0]) for s in s2v_lst] #takes max f_ext = [dionysus.Simplex([-1] + s[0], s[1][0][0]) for s in s2v_lst] #takes min ord_dict = {tuple(s[0]): s[1][-1][1] for s in s2v_lst} ext_dict = {tuple([-1] + s[0]): s[1][0][1] for s in s2v_lst} f_ord.sort(key=lambda s: (s.data, len(s))) f_ext.sort(key=lambda s: (-s.data, len(s))) #computes persistence f = dionysus.Filtration([dionysus.Simplex([-1], -float('inf'))] + f_ord + f_ext) m = dionysus.homology_persistence(f) dgms = [[[], []], [[], []], [[], []], [[], []]] #H0ord, H0ext, H1rel, H1ext for i in range(len(m)): dim = f[i].dimension() if m.pair(i) < i: continue # skip negative simplices to avoid double counting if m.pair( i ) != m.unpaired: #should be no unpaired apart from H0 from fictitious -1 vertex pos, neg = f[i], f[m.pair(i)] if pos.data != neg.data: #off diagonal if -1 in pos and -1 in neg: #rel1 dgms[2][0].append(ext_dict[tuple(neg)]) dgms[2][1].append(ext_dict[tuple(pos)]) elif -1 not in pos and -1 not in neg: #ord0 dgms[1][0].append(ord_dict[tuple(pos)]) dgms[1][1].append(ord_dict[tuple(neg)]) else: if dim == 0: #H0ext dgms[0][0].append(ord_dict[tuple(pos)]) dgms[0][1].append(ext_dict[tuple(neg)]) if dim == 1: #H1ext dgms[3][0].append(ext_dict[tuple(neg)]) dgms[3][1].append(ord_dict[tuple(pos)]) return dgms
def from_simplices(self, simplices): if not isinstance(simplices, dionysus.Filtration): simplices = dionysus.Filtration(simplices) # import pdb; pdb.set_trace() # Add cone point to force homology to finite length; Dionysus only gives out cycles of finite intervals spxs = [dionysus.Simplex([-1])] + [c.join(-1) for c in simplices] for spx in spxs: spx.data = 1 simplices.append(spx) # Compute persistence diagram persistence = dionysus.homology_persistence(simplices) diagrams = dionysus.init_diagrams(persistence, simplices) # Set all the results self._filtration = simplices self._diagram = diagrams[self.order] self._persistence = persistence self.barcode = np.array([(d.birth, d.death) for d in self._diagram]) self._build_cycles()
def fit(self, data): """ Generate Rips filtration and cycles for data. """ # Generate rips filtration maxeps = np.max(data.std(axis=0)) # TODO: is this the best choice? cpx = dionysus.fill_rips(data, self.order+1, maxeps) # Add cone point to force homology to finite length; Dionysus only gives out cycles of finite intervals spxs = [dionysus.Simplex([-1])] + [c.join(-1) for c in cpx] for spx in spxs: spx.data = 1 cpx.append(spx) # Compute persistence diagram persistence = dionysus.homology_persistence(cpx) diagrams = dionysus.init_diagrams(persistence, cpx) # Set all the results self._filtration = cpx self._diagram = diagrams[self.order] self._persistence = persistence self.barcode = np.array([(d.birth, d.death) for d in self._diagram]) self._build_cycles()
def dionysus_test(): import dionysus as d simplices = [([0, 6], 0.0035655512881059928), ([0, 5], 0.004388370816130452), ([0, 4], 0.024136039488717488), ([0, 3], 0.035381239705051776), ([3, 5], 0.035381239705051776), ([0, 1], 0.9824465164612051), #([1, 1], 0.9824465164612051), ([1, 3], 0.9824465164612051), ([1, 4], 0.9824465164612051), ([1, 5], 0.9824465164612051), ([1, 6], 0.9824465164612051), ([0, 2], 0.9999999997257268), ([1, 2], 0.9999999997257268), ([2, 2], 0.9999999997257268), ([2, 3], 0.9999999997257268), ([2, 4], 0.9999999997257268), ([2, 5], 0.9999999997257268), ([2, 6], 0.9999999997257268), ([0], 0.0016456390560489196), ([6], 0.0035655512881059928), ([5], 0.004388370816130452), ([4], 0.024136039488717488), ([3], 0.035381239705051776), ([1], 0.9824465164612051), ([2], 0.9999999997257268)] f = d.Filtration() for vertices, time in simplices: f.append(d.Simplex(vertices, time)) f.sort() m = d.homology_persistence(f) for i, c in enumerate(m): print(i, c)
def fix_dio_vert_nums(Cplx, vertind): ''' Helper function to adjust indexing of vertices in Dionysus from ``fill_rips`` function. Cplx: List of dio.Simplex's or a dio.Filtration Starting complex you want to adjust indices of vertind: int Starting index for vertices Returns ------- New complex with vertex indices adjusted by vertind. ''' New_Cplx = [] for s in Cplx: # s.data = data vlist = [] for v in s: vlist.append(v + vertind) s = dio.Simplex(vlist, s.data) New_Cplx.append(s) return New_Cplx
def conv_filtration(f, x, conv_weight_data, id_start_1, id_start_2, percentile=None, h0_births=None, stride=1): mat = conv_layer_as_matrix(conv_weight_data, x, stride) x = x.cpu().detach().numpy().reshape(-1) outer = np.absolute(mat * x) if h0_births is None: h0_births = np.zeros(x.shape) else: h0_births = h0_births.reshape(-1) if percentile is None: percentile_1 = 0 else: percentile_1 = np.percentile(outer, percentile) gtzx = np.argwhere(x > 0) h1_births = np.zeros(mat.shape[0]) # loop over each entry in the reshaped (column) x vector for xi in gtzx: # compute the product of each filter value with current x in iteration. all_xis = np.absolute(mat[:, xi] * x[xi]) max_xi = all_xis.max() # set our x filtration as the highest product if h0_births[xi] < max_xi: h0_births[xi] = max_xi # f.append(dion.Simplex([xi], max_xi)) gtpall_xis = np.argwhere(all_xis > percentile_1)[:, 0] # iterate over all products for mj in gtpall_xis: # if there is another filter-xi combination that has a higher # product, save this as the birth time of that vertex. if h1_births[mj] < all_xis[mj]: h1_births[mj] = all_xis[mj] f.append( dion.Simplex([xi + id_start_1, mj + id_start_2], all_xis[mj])) for i in np.argwhere(h0_births > 0): f.append(dion.Simplex([i + id_start_1], h0_births[i])) return f, h1_births
def Link(sigma, X): # inputs: # sigma - dionysus simplex # X - list of dionysus simplices link = [] for tau in X: if set(sigma).issubset(set(tau)): tau_sub_gamma = set(tau).difference(set(sigma)) link.append(d.Simplex(list(tau_sub_gamma))) return (link)
def compute_PD(self, simplices, sub=True, inf_flag='False'): def cmp(a, b): return (a > b) - (a < b) def compare(s1, s2, sub_flag=True): if sub_flag == True: if s1.dimension() > s2.dimension(): return 1 elif s1.dimension() < s2.dimension(): return -1 else: return cmp(s1.data, s2.data) elif sub_flag == False: return -compare(s1, s2, sub_flag=True) node_simplices, edge_simplices = list(), list() for simplex, time in simplices: if len(simplex) == 1: node_simplices.append((simplex, time)) elif len(simplex) == 2: edge_simplices.append((simplex, time)) else: raise Exception('Expect Dim of simplex be either 1 or 2') f_node, f_edge = d.Filtration(), d.Filtration() for simplex, time in node_simplices: f_node.append(d.Simplex(simplex, time)) f_node.sort() for simplex, time in edge_simplices: f_edge.append(d.Simplex(simplex, time)) f_edge.sort(reverse=True) m = d.homology_persistence(f_node) dgms = d.init_diagrams(m, f_node) if inf_flag == 'False': dgms = self.del_inf(dgms) # for some degenerate case, return dgm(0,0) if (dgms == []) or (dgms == None): return d.Diagram([[0,0]]) return dgms
def load_filtration(file): """ Load a filtration :param file: :return: """ f = di.Filtration() simplices = np.load(file) for vertices, data in simplices: f.append(di.Simplex(vertices, data)) return f
def collect_result(res): global nm global id for enum in res: nodes = enum[0] weight = enum[1] if len(nodes) == 1: if nodes[0] not in nm: nm[nodes[0]] = id id += 1 f.append(dion.Simplex([nm[nodes[0]]], weight)) else: f.append(dion.Simplex([nm[nodes[0]]], weight)) if len(nodes) == 2: if nodes[0] not in nm: nm[nodes[0]] = id id += 1 if nodes[1] not in nm: nm[nodes[1]] = id id += 1 f.append(dion.Simplex([nm[nodes[0]], nm[nodes[1]]], weight))
def init_freudenthal_2d(width, height): """ Freudenthal triangulation of 2d grid """ s = d.Filtration() # row-major format # 0-cells for i in range(height): for j in range(width): ind = i * width + j s.append(d.Simplex([ind])) # 1-cells for i in range(height): for j in range(width - 1): ind = i * width + j s.append(d.Simplex([ind, ind + 1])) for i in range(height - 1): for j in range(width): ind = i * width + j s.append(d.Simplex([ind, ind + width])) # 2-cells + diagonal 1-cells for i in range(height - 1): for j in range(width - 1): ind = i * width + j # diagonal s.append(d.Simplex([ind, ind + width + 1])) # 2-cells s.append(d.Simplex([ind, ind + 1, ind + width + 1])) s.append(d.Simplex([ind, ind + width, ind + width + 1])) return s
def compute_PD(self, simplices, sub=True, inf_flag='False', zigzag = False): def cmp(a, b): return (a > b) - (a < b) def compare(s1, s2, sub_flag=True): if sub_flag == True: if s1.dimension() > s2.dimension(): return 1 elif s1.dimension() < s2.dimension(): return -1 else: return cmp(s1.data, s2.data) elif sub_flag == False: return -compare(s1, s2, sub_flag=True) def zigzag_less(x, y): # x, y are simplex dimx, datax = x.dimension(), x.data dimy, datay = y.dimension(), y.data if dimx == dimy == 0: return datax <= datay elif dimx == dimy == 1: return datax >= datay else: return dimx < dimy f = d.Filtration() for simplex, time in simplices: f.append(d.Simplex(simplex, time)) if not zigzag: f.sort() if sub else f.sort(reverse=True) else: f.sort(zigzag_less, reverse=True) # print('After zigzag\n') # print_f(f) # simplices = [([2], 4), ([1, 2], 5), ([0, 2], 6),([0], 1), ([1], 2), ([0, 1], 3)] # f = d.Filtration() # for vertices, time in simplices: # f.append(d.Simplex(vertices, time)) # f.append(d.Simplex(vertices, time)) # f.sort(cmp=zigzag_less,reverse=True) # print_f(f) m = d.homology_persistence(f) dgms = d.init_diagrams(m, f) if inf_flag == 'False': dgms = self.del_inf(dgms) # for some degenerate case, return dgm(0,0) if (dgms == []) or (dgms == None): return d.Diagram([[0,0]]) return dgms
def build_filtered_complex(dims, indexes, time): """Build a filtered complex from dictionaries giving the dimensions, subsimplices, and times of entry :param dims: dictionary with keys giving simplex, values giving dimension :param indexes: Dictionary with keys giving the simplex, value giving the order in which simplex enters :param time: Dictionary with keys giving simplex, value giving time of entry :return: """ sortedkeys = sorted(indexes, key=indexes.get) f = d.Filtration() for key in sortedkeys: if dims[key] == 0: f.append(d.Simplex([indexes[key]], time[key])) elif dims[key] == 1: verts = list(key) vertices = [indexes[v] for v in verts] f.append(d.Simplex(vertices, time[key])) elif dims[key] == 2: verts = list(key) vertices = [indexes[v] for v in verts] f.append(d.Simplex(vertices, time[key])) return f
def init_line_complex(p): """ initialize 1D complex on the line Input: p - number of 0-simplices Will add (p-1) 1-simplices """ f = d.Filtration() for i in range(p - 1): c = d.closure([d.Simplex([i, i + 1])], 1) for j in c: f.append(j) return f
def init_net(self, axis, net): list(map(axis.axis, ('equal', 'off'))) self.plots['net'] = {} for i, s in enumerate(net.Salpha): s = dio.Simplex(*s) if s.dimension() == 0: x = net.plot_vertex(self.ax[0], s, False) self.plots['net'][i] = x[0] if isinstance(x, list) else x elif s.dimension() == 1: x = net.plot_edge(self.ax[0], s, False) self.plots['net'][i] = x[0] if isinstance(x, list) else x elif s.dimension() == 2: x = net.plot_triangle(self.ax[0], s, False, alpha=0.5) self.plots['net'][i] = x[0] if isinstance(x, list) else x
def filtration(self): if self._filtration != None: return self._filtration else: self._filtration = d.Filtration() nodes_so_far = [] for year in self.years: nodes_now = self.nodes_for_year[year] nodes_so_far.extend(nodes_now) for clique in self.cliques: if all([n in nodes_so_far for n in clique]): self._filtration.append(d.Simplex(clique, year)) self._filtration.sort() return self._filtration
def get_verts(simp): ''' Helper function to get all vertices of the input simplex Parameters ----------- simp: dio.Simplex Instance of Dionysus simplex class Returns ------- List of vertices in the simplex ''' if simp.dimension == 2: return [dio.Simplex([v], 0) for v in t] else: return set([s for s in simp.boundary()])
def test_issue47(): # init the complex/filtration # any filtration that produces a diagram of only infinite points will work simplicies = [ ([0], 0), ([1], 1), ] # create the filtration filtr = d.Filtration() for verts, idx in simplicies: simplex = d.Simplex(verts, idx) filtr.append(simplex) filtr.sort() # create the diagram m = d.homology_persistence(filtr) dgm = d.init_diagrams(m, filtr) d.plot.plot_diagram(dgm[0])
def test_dionysus_modification(): simplices = [([2], 4), ([1, 2], 5), ([0, 2], 6), ([0], 1), ([1], 2), ([0, 1], 3)] f = d.Filtration() for vertices, time in simplices: f.append(d.Simplex(vertices, time)) def compare(s1, s2, sub_flag=True): if sub_flag == True: if s1.dimension() > s2.dimension(): return 1 elif s1.dimension() < s2.dimension(): return -1 else: return cmp(s1.data, s2.data) elif sub_flag == False: return -compare(s1, s2, sub_flag=True) f.sort(cmp=compare) for s in f: print(s)
def AlexanderDual(X): # input: list of dionysus simplices X # output: facets of the Alexander Dual V = set() dim = -1 X = list(set(X)) for s in X: V = V.union(set(s)) dim = max(dim, s.dimension()) Id = np.eye(len(V)) M = np.zeros((len(X), len(V))) # one row per simplex # form simplicial incidence matrix for i in range(len(X)): for j in X[i]: M[i, j] = 1 # find maximal faces. Entry (i,j) is the size of intersection of face i and j M_max = np.matmul(M, M.transpose()) # entry (i,j) is true if face i is subset of face j M_max = M_max == np.sum(M, 1).reshape(M.shape[0], 1) nonfaces = [] rV = range(len(V)) Mt = M.transpose() for ix in range(2, dim + 2): combsMat = np.vstack( [np.sum(Id[list(x)], 0) for x in it.combinations(rV, ix)]) M_max = np.matmul(combsMat, Mt) M_max = M_max == ix if nonfaces == []: nonfaces = combsMat[np.sum(M_max, 1) == 0] else: nonfaces = np.vstack([nonfaces, combsMat[np.sum(M_max, 1) == 0]]) M = np.array(np.logical_not(nonfaces), dtype='float') M_max = np.matmul(M, M.transpose()) M_max = M_max == np.sum(M, 1).reshape(M.shape[0], 1) M = M[np.sum(M_max, 1) == 1] maxSimplices = [] for ix in range(M.shape[0]): maxSimplices.append(d.Simplex(list(np.where(M[ix] == 1)[0]))) return (maxSimplices)
def compute_static_filtration(self, x, hiddens, percentile=None): x_id = 0 f = dion.Filtration() mat = np.absolute( conv_layer_as_matrix(self.conv1.weight.data, x, self.conv1.stride[0])) x = x.cpu().detach().numpy().reshape(-1) if percentile is None: percentile_1 = 0 else: percentile_1 = np.percentile(mat, percentile) gtzx = np.argwhere(x > 0) h1_id_start = x.shape[0] h1_births = np.zeros(mat.shape[0]) # loop over each entry in the reshaped (column) x vector for xi in gtzx: # compute the product of each filter value with current x in iteration. all_xis = mat[:, xi] max_xi = all_xis.max() # set our x filtration as the highest product f.append(dion.Simplex([xi], max_xi)) gtpall_xis = np.argwhere(all_xis > percentile_1)[:, 0] # iterate over all products for mj in gtpall_xis: # if there is another filter-xi combination that has a higher # product, save this as the birth time of that vertex. if h1_births[mj] < all_xis[mj]: h1_births[mj] = all_xis[mj] f.append(dion.Simplex([xi, mj + h1_id_start], all_xis[mj])) h1 = hiddens[0].cpu().detach().numpy() h2_id_start = h1_id_start + h1.shape[0] mat = np.absolute(self.fc1.weight.data.cpu().detach().numpy()) h2_births = np.zeros(mat.shape[0]) if percentile is None: percentile_2 = 0 else: percentile_2 = np.percentile(mat, percentile) gtzh1 = np.argwhere(h1 > 0) for xi in gtzh1: all_xis = mat[:, xi] max_xi = all_xis.max() if h1_births[xi] < max_xi: h1_births[xi] = max_xi gtpall_xis = np.argwhere(all_xis > percentile_2)[:, 0] for mj in gtpall_xis: if h2_births[mj] < all_xis[mj]: h2_births[mj] = all_xis[mj] f.append( dion.Simplex([xi + h1_id_start, mj + h2_id_start], all_xis[mj])) # now add maximum birth time for each h1 hidden vertex to the filtration. for i in np.argwhere(h1_births > 0): f.append(dion.Simplex([i + h1_id_start], h1_births[i])) h2 = hiddens[1].cpu().detach().numpy() h3_id_start = h2_id_start + h2.shape[0] mat = np.absolute(self.fc2.weight.data.cpu().detach().numpy()) h3_births = np.zeros(mat.shape[0]) if percentile is None: percentile_3 = 0 else: percentile_3 = np.percentile(mat, percentile) gtzh2 = np.argwhere(h2 > 0) for xi in gtzh2: all_xis = mat[:, xi] max_xi = all_xis.max() if h2_births[xi] < max_xi: h2_births[xi] = max_xi gtpall_xis = np.argwhere(all_xis > percentile_3)[:, 0] for mj in gtpall_xis: if h3_births[mj] < all_xis[mj]: h3_births[mj] = all_xis[mj] f.append( dion.Simplex([xi + h2_id_start, mj + h3_id_start], all_xis[mj])) # now add maximum birth time for each h2 hidden vertex to the filtration. for i in np.argwhere(h2_births > 0): f.append(dion.Simplex([i + h2_id_start], h2_births[i])) # now add maximum birth time for each h3 hidden vertex to the filtration. for i in np.argwhere(h3_births > 0): f.append(dion.Simplex([i + h3_id_start], h3_births[i])) print('filtration size', len(f)) print('Sorting filtration...') f.sort(reverse=True) return f
#f.append(dio.Simplex(v, t)) simplices.append([(b_1, it[0], it[1]), t]) finish = time.time() print('Time taken to create and add 0, 1, 2-simplices:', finish - start) # Evaluate the persistence homologies input( 'Press key to add and sort simplices, and evaluate persistent homology by Dionysus2...' ) # Create the blank filtration f = dio.Filtration() for i, simplex in enumerate(simplices): f.append(dio.Simplex(simplex[0], simplex[1])) # Sort the simplices f.sort() start = time.time() per_hom = dio.homology_persistence(f) finish = time.time() print('Time taken to evaluate persistent homology by Dionysus:', finish - start) input( 'Press key to add and sort simplices, and evaluate persistent homology by Manu...' ) start = time.time() all_columns = [[], [], []] filtration_list = []
def setup_Zigzag(self, k=2): ''' Helper function for ``run_Zigzag`` that sets up inputs needed for Dionysus' zigzag persistence function. This only works for a fixed radius r. Parameters ---------- k: int, optional Max dimension for rips complex (default is 2) Returns ------- filtration: dio.Filtration Dionysis filtration containing all simplices that exist in zigzag sequence times: list List of times, where times[i] is a list containing [a,b] where simplex i appears at time a, and disappears at time b ''' # renames edges in the list based on the vert labels # so an edge [0,5] becomes [vert_labels[0], vert_labels[5]] def rename_edges(edge_list, vert_labels): vert_dict = {i: vert_labels[i] for i in range(len(vert_labels))} return np.vectorize(vert_dict.__getitem__)(edge_list) def make_undirected(A): for i in range(len(A)): for j in range(i): if A[i, j] > 0 or A[j, i] > 0: A[i, j] = 1 A[j, i] = 1 else: A[i, j] = 0 A[j, i] = 0 return A def fix_vert_nums(simp, labels): vlist = [] for v in simp: vlist.append(labels[v]) return vlist def get_tris(A, labels): A_u = make_undirected(A) A_u[A_u != 0] = 0.1 A_u[A_u == 0] = 10 np.fill_diagonal(A_u, 0) f = dio.fill_rips(squareform(A_u), k=2, r=1) tris = [fix_vert_nums(i, labels) for i in f if i.dimension() == 2] return tris simps_list = [] times_list = [] verts = np.unique(np.concatenate(self.vert_labels)) num_verts = len(verts) # Handle vertices... for v in verts: simps_list.append(dio.Simplex([v], 0)) s_times = [] simp_in = False # Find time simplex enters filtration for i in range(len(self.networks)): if v in self.vert_labels[i] and simp_in == False: if self.cplx_type == 'union': if i == 0: st = 0 else: st = i - 0.5 s_times.append(st) elif self.cplx_type == 'intersection': s_times.append(i) else: print('cplx_type not recognized...\nQuitting') return [], [] simp_in = True # Find time simplex exits filtration if v not in self.vert_labels[i] and simp_in == True: if self.cplx_type == 'union': s_times.append(i) elif self.cplx_type == 'intersection': s_times.append(i - 0.5) else: print('cplx_type not recognized...\nQuitting') return [], [] simp_in = False times_list.append(s_times) if self.verbose: print(f"Added {num_verts} vertices to filtration.") # list of lists # edges_lists[i] contains the edges in network[i] with correct vert labels # note edges are sorted in vert label order so edges are no longer directed edges_lists = [ np.sort(rename_edges( np.hstack([np.where(self.networks[i] != 0)]).T, self.vert_labels[i]), axis=1).tolist() for i in range(len(self.networks)) ] # list of unique edges across all networks unique_edges = np.unique(np.vstack( [np.array(es) for es in edges_lists]), axis=0).tolist() num_edges = len(unique_edges) # Handle edges... for e in unique_edges: simps_list.append(dio.Simplex(e, 0)) s_times = [] simp_in = False for i in range(len(self.networks)): if e in edges_lists[i] and simp_in == False: if self.cplx_type == 'union': if i == 0: st = 0 else: st = i - 0.5 s_times.append(st) elif self.cplx_type == 'intersection': s_times.append(i) else: print('cplx_type not recognized...\nQuitting') return [], [] simp_in = True if not e in edges_lists[i] and simp_in == True: if self.cplx_type == 'union': s_times.append(i) elif self.cplx_type == 'intersection': s_times.append(i - 0.5) simp_in = False times_list.append(s_times) if self.verbose: print(f"Added {num_edges} edges to filtration.") # Handle triangles... tri_lists = [ get_tris(self.networks[i], self.vert_labels[i]) for i in range(len(self.networks)) ] unique_tris = np.unique(np.vstack( [np.array(ts) for ts in tri_lists if ts != []]), axis=0).tolist() num_tris = len(unique_tris) for t in unique_tris: simps_list.append(dio.Simplex(t, 0)) s_times = [] simp_in = False for i in range(len(self.networks)): if t in tri_lists[i] and simp_in == False: if self.cplx_type == 'union': if i == 0: st = 0 else: st = i - 0.5 s_times.append(st) elif self.cplx_type == 'intersection': s_times.append(i) else: print('cplx_type not recognized...\nQuitting') return [], [] simp_in = True if t not in tri_lists[i] and simp_in == True: if self.cplx_type == 'union': s_times.append(i) elif self.cplx_type == 'intersection': s_times.append(i - 0.5) simp_in = False times_list.append(s_times) if self.verbose: print(f"Added {num_tris} triangles to filtration.") f_st = time.time() filtration = dio.Filtration(simps_list) f_end = time.time() return filtration, times_list
import dionysus as d import numpy as np if __name__ == '__main__': print('Testing a TDA output for Dionysus...') vertex1 = 0 vertex2 = 1 vertex3 = 2 print('Making simplex from verts: ', vertex1, vertex2, vertex3) s=d.Simplex([vertex1,vertex2,vertex3]) print("Here is the simplex: ", s) print("Its dimension is: ", s.dimension()) print("And its boundary...") for sb in s.boundary(): print(sb) print("Great - So we can work with simplecies, but we can also work with points") print("Here is an array (Must be numpy)") points = np.array([[0.0,1.0],[2.0,0.0],[0.0,0.0]]) print(points)
fig = plt.figure() ax = fig.add_subplot(111) ax.set_xlim(-1.1,1.1) ax.set_ylim(-1.1,1.1) ax.scatter(circ_data2[:,0],circ_data2[:,1],c="k") ax.scatter(circ_data2[-1,0],circ_data2[-1,1],c="r") ax.set_aspect("equal") plt.show() #get each barcode #alpha filtration TDA test_comp = circ_alpha1[0] test_bts = circ_alpha1[1] test_f = d.Filtration() for j in range(len(test_comp)): test_f.append(d.Simplex(test_comp[j],test_bts[j])) p = d.homology_persistence(test_f) dgms1 = d.init_diagrams(p, test_f) #scatters d.plot.plot_diagram(dgms1[0]) d.plot.plot_diagram(dgms1[1]) plt.show() #alpha filtration TDA test_comp = circ_alpha2[0] test_bts = circ_alpha2[1] test_f = d.Filtration() for j in range(len(test_comp)): test_f.append(d.Simplex(test_comp[j],test_bts[j])) p = d.homology_persistence(test_f)
def compute_dynamic_filtration_no_inf(self, x, hiddens, percentile=0, return_nm=False): id = 0 f = dion.Filtration() f.append(dion.Simplex([-1], 0)) enums = [] nm = {(-1, 0, 0): -1} params = self.params percentiles = np.zeros((len(params))) def collect_result(res): nonlocal id nonlocal f nonlocal nm for enum in res: nodes = enum[0] weight = enum[1] if len(nodes) == 1: if nodes[0] not in nm: nm[nodes[0]] = id id += 1 f.append(dion.Simplex([nm[nodes[0]]], weight)) else: f.append(dion.Simplex([nm[nodes[0]]], weight)) f.append(dion.Simplex([nm[nodes[0]], -1], 0)) if len(nodes) == 2: if nodes[0] not in nm: nm[nodes[0]] = id id += 1 if nodes[1] not in nm: nm[nodes[1]] = id id += 1 f.append(dion.Simplex([nm[nodes[0]], nm[nodes[1]]], weight)) x = x.cpu().detach().numpy() num_channels = x.shape[0] l = 0 percentiles[l] = np.percentile( np.absolute(hiddens[l].cpu().detach().numpy()), percentile) hn = hiddens[l].cpu().detach().numpy() nlc = hn.reshape((hn.shape[0], -1)).shape[1] stride = 1 for c in range(num_channels): p = params[l].weight.data[:, c, :, :] mat = conv_layer_as_matrix(p, x[c], stride) m1, h0_births, h1_births = conv_filtration_fast2( x[c], mat, l, c, nlc, percentile=percentiles[l]) # enums = m1 # enums += [([spec_hash((l,c,i[0]))], h0_births[i].item()) for i in np.argwhere(h0_births > percentile)] enums = [] enums += [([spec_hash( (l + 1, i[0] // nlc, i[0] % nlc))], h1_births[i].item()) for i in np.argwhere(h1_births > percentile)] collect_result(enums) h1 = hiddens[l].cpu().detach().numpy() l = 1 percentiles[l] = np.percentile( np.absolute(hiddens[l].cpu().detach().numpy()), percentile) p = params[l] m1, h0_births, h1_births = linear_filtration_fast2( h1, p, l, 0, percentile=percentiles[l]) enums += m1 comp_percentile = percentiles[ l - 1] if percentiles[l - 1] < percentiles[l] else percentiles[l] enums += [([spec_hash((l, c, i[0]))], h0_births[i]) for i in np.argwhere(h0_births > comp_percentile)] h1 = hiddens[l].cpu().detach().numpy() l = 2 percentiles[l] = np.percentile( np.absolute(hiddens[l].cpu().detach().numpy()), percentile) p = params[l] m1, h0_births, h1_births_2 = linear_filtration_fast2( h1, p, l, 0, percentile=percentiles[l]) enums += m1 max1 = np.maximum.reduce([h0_births, h1_births]) comp_percentile = percentiles[ l - 1] if percentiles[l - 1] < percentiles[l] else percentiles[l] enums += [([spec_hash((l, 0, i[0]))], max1[i]) for i in np.argwhere(max1 > comp_percentile)] enums += [([spec_hash((l + 1, 0, i[0]))], h1_births_2[i]) for i in np.argwhere(h1_births_2 > percentiles[l])] collect_result(enums) # h1_id_start = x.cpu().detach().numpy().reshape(-1).shape[0] # print('h1_id_start', h1_id_start) # f, h1_births = conv_filtration(f, x[0], self.conv1.weight.data[:,0,:,:], 0, h1_id_start, percentile=percentile) # # h2_id_start = h1_id_start + hiddens[0].cpu().detach().numpy().shape[0] # print('h2_id_start', h2_id_start) # f, h2_births = linear_filtration(f, hiddens[0], self.fc1, h1_births, h1_id_start, h2_id_start, percentile=percentile, last=False) # # h3_id_start = h2_id_start + hiddens[1].cpu().detach().numpy().shape[0] # print('h3_id_start', h3_id_start) # f = linear_filtration(f, hiddens[1], self.fc2, h2_births, h2_id_start, h3_id_start, percentile=percentile, last=True) print('filtration size', len(f)) f.sort(reverse=True) if return_nm: return f, nm else: return f