def add_dgm(dgm1, dgm2): """ add(overlay) two dgms """ diag1 = dgm2diag(dgm1) diag2 = dgm2diag(dgm2) data = diag1 + diag2 if len(data) ==0: return d.Diagram([[0,0]]) return d.Diagram(data)
def plottwodgms(dgm1, dgm2): diag1 = np.array(dgm2diag(dgm1)) diag2 = np.array(dgm2diag(dgm2)) plt.scatter(diag1[:, 0], diag1[:, 1], alpha=0.3) plt.scatter(diag2[:, 0], diag2[:, 1], alpha=0.3) m = dgmdist(dgm1, dgm2) plt.title('bd is %s, sw is %s' % (m.bd_dist(), m.sw_dist())) plt.show()
def get_diagram(self, g, key='fv', subflag='True', one_homology_flag=False, parallel_flag=False, zigzag=False): """ :param g: networkx graph with fv computed on each node and edge :param key: fv. This is the key to access filtration function value :param subflag: 'True' if sub level filtration used. 'False' if superlevel filtration used. :param one_homology_flag: ignore for now. :param parallel_flag: ignore for now. :param zigzag: Set to be true if you want to use combined filtration. (set filtration for nodes and edges seprately, instead of using node filtration or edge filtration.) :return: Persistence diagram """ # only return 0-homology of sublevel filtration TODO: include one homology # type can be tuple or pd. tuple can be parallized, pd cannot. g = nx.convert_node_labels_to_integers(g) simplices = self.get_simplices(g, key=key) if one_homology_flag: epd_dgm = self.epd(g, pd_flag=False)[1] epd_dgm = self.post_process(epd_dgm) return epd_dgm super_dgms = self.compute_PD(simplices, sub=False) sub_dgms = self.compute_PD( simplices, sub=True) if not zigzag else self.compute_PD( simplices, zigzag=True) _min = min([g.node[n][key] for n in g.nodes()]) _max = max([g.node[n][key] for n in g.nodes() ]) + 1e-5 # avoid the extra node lies on diagonal p_min = d.Diagram([(_min, _max)]) p_max = d.Diagram([(_max, _min)]) sub_dgms[0].append(p_min[0]) super_dgms[0].append(p_max[0]) if subflag == 'True': return sub_dgms[0] if not parallel_flag else dgm2diag(sub_dgms[0]) elif subflag == 'False': return super_dgms[0] if not parallel_flag else dgm2diag( super_dgms[0]) else: raise Exception('subflag can be either True or False')
def permute(dgm, seed=42, seed_flag = True): """ :param dgm: diagram in dionysus form :param seed: random seed :param seed_flag: if set seed or not :return: """ # dgm = randomdgms(10)[0] if seed_flag: np.random.seed(seed) tmp = dgm2diag(dgm) # tmp is a list of tuples coordinates = [p[0] for p in tmp] + [p[1] for p in tmp] np.random.shuffle(coordinates) assert len(coordinates) % 2 == 0 n_removed = 0 diag = [] for i in range(0, len(coordinates), 2): b, d = coordinates[i], coordinates[i+1] if abs(b-d) < 1e-3: # dionysus does not allow points that is too close to diagonal n_removed += 1 continue tmp = tuple((min(b, d), max(b, d))) diag.append(tmp) assert len(diag) + n_removed == len(coordinates)//2 if len(diag) == 0: diag = [(0,0)] return diag2dgm(diag)
def overlay(self): diags = [] for dgm in self.dgms: diag = dgm2diag(dgm) diags.append(np.array(diag)) # diags = [np.random.random((3, 2)), np.random.random((2,2))] res = np.concatenate(tuple(diags), axis=0) # array res = array2diag(res) res = diag2dgm(res) return res
def dgm_statfeat(dgm): """ stats feat of a dgm. Concatenation of stats of birth/death/life time """ # dgm = d.Diagram([(2, 3), (3, 4)]) diag = dgm2diag(dgm) birthtime = [p[0] for p in diag] deathtime = [p[1] for p in diag] lifetime = [abs(p[1] - p[0]) for p in diag] feat = np.concatenate( (statfeat(birthtime), statfeat(deathtime), statfeat(lifetime))) return feat
def get_diagram(self, g, key='fv', subflag = 'True', one_homology_flag=False, parallel_flag = False, zigzag = False): # only return 0-homology of sublevel filtration TODO: include one homology # type can be tuple or pd. tuple can be parallized, pd cannot. """ for a graph with a function on its nodes or edges defined, compute its 0-persistence diagram. :param g: graph :param key: 'fv' :param subflag: :param one_homology_flag: :param parallel_flag: :param zigzag: True of edge based filtration :return: """ g = nx.convert_node_labels_to_integers(g) simplices = self.get_simplices(g, key = key) if one_homology_flag: epd_dgm = self.epd(self, g, pd_flag=False)[1] epd_dgm = self.post_process(epd_dgm) return epd_dgm super_dgms = self.compute_PD(simplices, sub=False) sub_dgms = self.compute_PD(simplices, sub=True) if not zigzag else self.compute_PD(simplices, zigzag=True) _min = min([g.node[n][key] for n in g.nodes()]) _max = max([g.node[n][key] for n in g.nodes()])+ 1e-5 # avoid the extra node lies on diagonal p_min = d.Diagram([(_min, _max)]) p_max = d.Diagram([(_max, _min)]) sub_dgms[0].append(p_min[0]) super_dgms[0].append(p_max[0]) if subflag=='True': return sub_dgms[0] if not parallel_flag else dgm2diag(sub_dgms[0]) elif subflag=='False': return super_dgms[0] if not parallel_flag else dgm2diag(super_dgms[0]) else: raise Exception('subflag can be either True or False')
def coordinate(dgm, dim = 100): dgm = dgm_filter(dgm) tmp = dgm2diag(dgm) coordinates = [p[0] for p in tmp] + [p[1] for p in tmp] tor = 1e-3 try: assert -1 -tor <= min(coordinates) assert max(coordinates) <= 1 + tor except AssertionError: norm = np.max(np.abs(np.array(coordinates))) coordinates = [num/float(norm) for num in coordinates] # print('min and max of coordinates is %s and %s. Exit'%(min(coordinates), max(coordinates))) # sys.exit() vec,_ = np.histogram(coordinates, bins=dim, range=[-1,1]) return vec.reshape((1,dim))
def fake_diagram(g, cardinality = 2, attribute='deg', seed=42, true_dgm = 'null'): random.seed(seed) sample_pool = nx.get_node_attributes(g, attribute).values() if true_dgm != 'null': tmp = dgm2diag(true_dgm) # tmp is array sample_pool = [p[0] for p in tmp] + [p[1] for p in tmp] try: sample = random.choice(sample_pool, size=2*cardinality, replace=False) except: sample = random.choice(sample_pool, size=2 * cardinality, replace=True) assert set(sample).issubset(set(sample_pool)) dgm = [] for i in range(0, len(sample),2): x_ = sample[i] y_ = sample[i+1] dgm.append((min(x_, y_), max(x_, y_)+1e-3)) return d.Diagram(dgm)
def data_interface(self, dgm, dynamic_range_flag=True): # from dgm to data/max/min for p in dgm: assert p.death >= p.birth data = [tuple(i) for i in dgm2diag(dgm)] try: [list1, list2] = zip(*data) except: print('Problem') list1 = [0] list2 = [1e-5] # adds a dummy 0 if dynamic_range_flag == True: min_ = min(min(list1), min(list2)) max_ = max(max(list1), max(list2)) std_ = (np.std(list1) + np.std(list2)) / 2.0 elif dynamic_range_flag == False: min_ = -5 max_ = 5 std_ = 3 return {'data': data, 'max': max_ + std_, 'min': min_ - std_}
def dgms2swdgm(dgms): swdgms = [] for dgm in dgms: diag = dgm2diag(dgm) swdgms += [np.array(diag)] return swdgms