def test_nested_boundary(): delta_k = Boundary() delta_k.compute_boundary(KSimplex([1, 2, 3])) print delta_k for sign, kmin1_simpl in delta_k.get_boundary(): # print kmin1_simpl.k delta_kmin1 = Boundary() delta_kmin1.compute_boundary(kmin1_simpl) print delta_kmin1
def test_nested_boundary_simplicialcomplex(): sigma = SimplicialComplex() sigma.add_simplex_fromfile('test_simplexfromfile.txt') for k in xrange(sigma.maxK + 1): print str(k) + '-th Chain group:' for k_sim in sigma.get_allkth_simplices(k): delta_k = Boundary() delta_k.compute_boundary(k_sim) print 'Boundary of: ', str(k_sim), ': ', str(delta_k)
def compute_cohomology(value=None): id_to_degree_map = {} # key = id, value = filtration appearence/degree. cardinalities = {} unmarked = { } # key = card value = list [] of unmarked simplices of that cardinality unmarked_basis = {} # key = id, value = set of ids try: while True: if value is None: value = (yield (-1, -1, -1)) birth = death = value.degree # since, we ignore such cases typically. dim = value.k # Though theoretically its not the right thing to do. try: if value.k < 0: # meaning i want to just go throw indices for infinity intervals flag = False for card in unmarked.keys(): for id_sigma in unmarked.get(card, []): birth = id_to_degree_map[id_sigma] death = INF flag = True value = (yield (birth, death, card - 1)) unmarked[card].remove(id_sigma) if flag is False: yield (-1, -1, -1) elif value.k == 0: # Vertices cardinalities[value.id] = value.k + 1 id_to_degree_map[value.id] = value.degree list_of_unmarked = unmarked.get(value.k + 1, []) if list_of_unmarked: unmarked[value.k + 1].append(value.id) else: unmarked[value.k + 1] = [value.id] unmarked_basis[value.id] = set([value.id]) value = (yield (birth, death, dim)) else: # 1-simplex, 2-simplex, etc. destroyer_flag = False most_recently_killed_degree = -1 most_recently_killed_id = -1 list_bases_toupdate = [ ] # list of id whose bases needs update boundary_obj = Boundary() # list_of_unmarked = [] boundary_set = set([]) card_boundary = value.k for sign, boundary in boundary_obj.compute_boundary(value): # constuct string repr of the simplex boundary_str = '|'.join( [str(b) for b in boundary.kvertices]) id_boundary = getId(boundary_str) boundary_set = boundary_set.union([id_boundary]) # for each simplex of cardinality card_boundary, check whether # the corresponding boundary set intersection is empty or have cardinality even for id_sigma in unmarked.get(card_boundary, []): basis_sigma = unmarked_basis.get(id_sigma) intersecting_set = basis_sigma.intersection( boundary_set) len_intersecting_set = len(intersecting_set) if len_intersecting_set % 2: # odd => destroyer destroyer_flag = True list_bases_toupdate.append(id_sigma) if id_to_degree_map[ id_sigma] > most_recently_killed_degree: most_recently_killed_id = id_sigma most_recently_killed_degree = id_to_degree_map[ id_sigma] # If it is a destroyer simplex/ -ve simplex. if destroyer_flag: birth = most_recently_killed_degree death = value.degree dim = cardinalities[most_recently_killed_id] - 1 unmarked[dim + 1].remove(most_recently_killed_id) # update the bases for all ids in list_bases_toupdate except most_recently_killed_id for id in list_bases_toupdate: if id != most_recently_killed_id: unmarked_basis[id].symmetric_difference_update( unmarked_basis[most_recently_killed_id]) del unmarked_basis[most_recently_killed_id] unmarked_basis[value.id] = set([value.id]) id_to_degree_map[value.id] = value.degree value = (yield (birth, death, dim)) else: # New cocycle. A +ve simplex/creator. cardinalities[value.id] = value.k + 1 list_of_unmarked = unmarked.get(value.k + 1, []) if list_of_unmarked: unmarked[value.k + 1].append(value.id) else: unmarked[value.k + 1] = [value.id] unmarked_basis[value.id] = set([value.id]) id_to_degree_map[value.id] = value.degree value = (yield (birth, death, dim)) # we must add the basis for value.id irrespective of it being creator or destroyer except Exception, e: value = e finally: # print "Don't forget to clean up when 'close()' is called." # del indices del id_to_degree_map del cardinalities del unmarked del unmarked_basis
def compute(self): """ Compute the persistent cohomology """ unmarked = { } # key = card value = list [] of unmarked simplices' id of that cardinality unmarked_basis = { } # key = id, value = set of ids whose linear combination makes the basis for sigma in self.filtration_ar: if sigma.k == 0: # Vertices list_of_unmarked = unmarked.get(sigma.k + 1, []) if list_of_unmarked: if sigma.id not in unmarked[sigma.k + 1]: unmarked[sigma.k + 1].append( sigma.id) # avoid repeatedly storing an id unmarked_basis[sigma.id] = {sigma.id} else: unmarked[sigma.k + 1] = [sigma.id] unmarked_basis[sigma.id] = {sigma.id} else: destroyer_flag = False most_recently_killed_degree = -1 most_recently_killed_id = -1 list_bases_toupdate = [] # list of id whose bases needs update boundary_obj = Boundary() # list_of_unmarked = [] boundary_set = set([]) card_boundary = sigma.k for sign, boundary in boundary_obj.compute_boundary(sigma): # constuct string repr of the simplex boundary_str = '|'.join( [str(b) for b in boundary.kvertices]) id_boundary = getId(boundary_str) boundary_set = boundary_set.union([id_boundary]) # for each simplex of cardinality card_boundary, check whether # the corresponding boundary set intersection is empty or have even cardinality for id_sigma in unmarked.get(card_boundary, []): basis_sigma = unmarked_basis.get(id_sigma) intersecting_set = basis_sigma.intersection(boundary_set) len_intersecting_set = len(intersecting_set) if len_intersecting_set % 2: # odd => destroyer destroyer_flag = True list_bases_toupdate.append(id_sigma) deg_id_sigma = self.filtration_ar[ self.simplexid_to_indexmap[id_sigma]].degree if deg_id_sigma > most_recently_killed_degree: most_recently_killed_id = id_sigma most_recently_killed_degree = deg_id_sigma # else: # # When both id_sigma and most_recently_killed_id have same degree, we resolve the ordering # # by their index in the filtration_ar # if self.simplexid_to_indexmap[id_sigma] > self.simplexid_to_indexmap[ # most_recently_killed_id] and deg_id_sigma == most_recently_killed_degree: # most_recently_killed_id = id_sigma # most_recently_killed_degree = deg_id_sigma # If it is a destroyer simplex/ -ve simplex. if destroyer_flag: birth = most_recently_killed_degree death = sigma.degree simplex_index = self.simplexid_to_indexmap[ most_recently_killed_id] simplex_to_destroy = self.filtration_ar[simplex_index] assert isinstance(simplex_to_destroy, KSimplex) dim = simplex_to_destroy.k self.intervals[dim].append((birth, death)) # mark this id. we only keep unmarked ids, unmarked == pivot unmarked[dim + 1].remove(most_recently_killed_id) # update the bases for all ids in list_bases_toupdate except most_recently_killed_id for id in list_bases_toupdate: if id != most_recently_killed_id: unmarked_basis[id].symmetric_difference_update( unmarked_basis[most_recently_killed_id]) del unmarked_basis[most_recently_killed_id] unmarked_basis[sigma.id] = {sigma.id} else: # New cocycle. A +ve simplex/creator. list_of_unmarked = unmarked.get(sigma.k + 1, []) if list_of_unmarked: if sigma.id not in unmarked[sigma.k + 1]: unmarked[sigma.k + 1].append(sigma.id) unmarked_basis[sigma.id] = {sigma.id} else: unmarked[sigma.k + 1] = [sigma.id] unmarked_basis[sigma.id] = {sigma.id} for card in unmarked.keys(): for id_sigma in unmarked.get(card, []): birth = self.filtration_ar[ self.simplexid_to_indexmap[id_sigma]].degree death = INF self.intervals[card - 1].append((birth, death))
def test_boundary_op(): delta = Boundary() delta.compute_boundary(KSimplex([1, 2, 3])) print delta