added minimalModel.py
This commit is contained in:
parent
c5cee786ae
commit
ec5c49be30
257
minimalModel.py
Normal file
257
minimalModel.py
Normal file
@ -0,0 +1,257 @@
|
||||
def update_cdga(gca, diff_dict={}):
|
||||
|
||||
gens_dict = gca.gens_dict()
|
||||
differentials = {}
|
||||
if diff_dict:
|
||||
for gen_name in diff_dict.keys():
|
||||
gen = gens_dict[gen_name]
|
||||
product_gens = diff_dict[gen_name]
|
||||
gen0 = gens_dict[product_gens[0]]
|
||||
if type(product_gens[1]) == int: # is a power
|
||||
power = product_gens[1]
|
||||
mult = gen0
|
||||
for i in range(1, power):
|
||||
mult *= gen0
|
||||
differentials.update({gen:mult})
|
||||
else:
|
||||
gen1 = gens_dict[product_gens[1]]
|
||||
differentials.update({gen:gen0*gen1})
|
||||
# print("differentials", differentials)
|
||||
return gca.cdg_algebra(differentials)
|
||||
|
||||
|
||||
def has_preimage(M, element):
|
||||
|
||||
d = M.differential()
|
||||
deg = element.degree()-1
|
||||
# print("differential of ", element, "degree: ", deg)
|
||||
Md = d.differential_matrix(deg)
|
||||
gens = M.basis(deg)
|
||||
try:
|
||||
solution = Md.solve_left(vector(QQ,element.basis_coefficients()))
|
||||
primitive = sum(map(lambda coef, gen: coef*gen, solution, gens))
|
||||
print(element, " has preimage ", primitive)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def injectivity_step(M, phi, check_dim, names,
|
||||
degrees, differentials, index=0, depth=0, max_depth=5):
|
||||
|
||||
print("Injectivity at dimension ", check_dim)
|
||||
if depth > max_depth:
|
||||
return [M, phi, names, degrees, differentials, True]
|
||||
deg = check_dim -1
|
||||
gens = [g for g in M.gens() if g.degree() < check_dim]
|
||||
# gens.sort(reverse=True)
|
||||
gen_products = []
|
||||
for i in range(len(gens)):
|
||||
e0 = gens[i]
|
||||
d = e0.degree()
|
||||
mcd = gcd(d, check_dim)
|
||||
if d%2 == 0 and mcd == d:
|
||||
power = True
|
||||
exp = check_dim / d
|
||||
mult = e0
|
||||
for j in range(1,exp-1):
|
||||
mult *= e0
|
||||
gen_products.append([e0, mult, power, exp])
|
||||
for j in range(i+1,len(gens)):
|
||||
power = False
|
||||
e1 = gens[j]
|
||||
if e0.degree() + e1.degree() == check_dim:
|
||||
gen_products.append([e0, e1, power])
|
||||
# print("products at dim ",check_dim,": ", gen_products)
|
||||
new_M = M
|
||||
new_phi = phi
|
||||
new_names = names
|
||||
new_degrees = degrees
|
||||
new_differentials = differentials
|
||||
for pair in gen_products:
|
||||
# Looking at the minimal model side
|
||||
gen0 = pair[0]
|
||||
deg_0 = gen0.degree()
|
||||
gen1 = pair[1]
|
||||
deg_1 = gen1.degree()
|
||||
M_product = gen0*gen1
|
||||
# Looking at the AplK side
|
||||
gen0_name = list(M.gens_dict().keys())[list(M.gens_dict().values()).index(gen0)]
|
||||
aplk_gen0 = phi[deg_0][gen0_name]
|
||||
is_power = pair[2]
|
||||
power = 0
|
||||
if is_power:
|
||||
power = pair[3]
|
||||
aplk_gen1 = aplk_gen0
|
||||
for i in range(1, power):
|
||||
aplk_gen1 *= aplk_gen0
|
||||
else:
|
||||
gen1_name = list(M.gens_dict().keys())[list(M.gens_dict().values()).index(gen1)]
|
||||
aplk_gen1 = phi[deg_1][gen1_name]
|
||||
aplk_product = aplk_gen0*aplk_gen1
|
||||
A = aplk_product.parent()
|
||||
# Check conditions
|
||||
if (M_product == M(0)) and (aplk_product == A.null_element()): # zero element
|
||||
pass
|
||||
elif (M_product == M(0)) and (aplk_product != A.null_element()): #check
|
||||
if aplk_product.is_closed():
|
||||
pass #trivial cohomology class (assuming aplk_product has preimage by differential)
|
||||
else:
|
||||
raise ValueError('zero associated to a non-closed element in AplK')
|
||||
elif (M_product.differential() != 0): # is not closed
|
||||
print("The element ",M_product, " is not closed")
|
||||
pass
|
||||
elif (M_product.differential() == 0) and aplk_product.is_closed() and has_preimage(M, M_product):
|
||||
pass #trivial cohomology class (assuming aplk_product has preimage by differential)
|
||||
elif (M_product.differential() == 0) and aplk_product.is_closed(): #key step because M_product doesn't have preimage
|
||||
new_gen = 'y'+str(deg)+'_'+str(index)
|
||||
if aplk_product != A.null_element():
|
||||
try:
|
||||
preimage = aplk_product.solve_primitive()
|
||||
except ValueError:
|
||||
print(" The element ",M_product, " has non trivial cohomology class. No generator added.")
|
||||
continue # we don't add a new generator because the element has non trivial cohomology class
|
||||
phi_new_gen = {new_gen: preimage}
|
||||
else:
|
||||
phi_new_gen = {new_gen: A.null_element()}
|
||||
print(" Proceed to kill", M_product, " because has associated trivial cohomology class")
|
||||
print("Adding generator "+new_gen)
|
||||
new_names = names + [new_gen]
|
||||
new_degrees = tuple(list(degrees)+[deg])
|
||||
new_differentials = copy.deepcopy(differentials)
|
||||
if not is_power:
|
||||
new_differentials.update({new_gen: [gen0_name, gen1_name]})
|
||||
else:
|
||||
new_differentials.update({new_gen: [gen0_name, int(power)]})
|
||||
gca = GradedCommutativeAlgebra(QQ, names=new_names, degrees=new_degrees)
|
||||
new_M = update_cdga(gca, new_differentials)
|
||||
new_phi = copy.deepcopy(phi)
|
||||
d = new_phi[deg]
|
||||
d.update(phi_new_gen)
|
||||
return injectivity_step(new_M, new_phi, check_dim, new_names,
|
||||
new_degrees, new_differentials, index=index+1, depth=depth+1, max_depth=max_depth)
|
||||
else:
|
||||
pass
|
||||
|
||||
return [new_M, new_phi, new_names, new_degrees, new_differentials, False]
|
||||
|
||||
def get_unmapped_generators(dim, coho_aplk, coho_gens, correspondence):
|
||||
|
||||
dimensions = list(correspondence.keys())
|
||||
unmmaped_elements = copy.deepcopy(coho_aplk)
|
||||
for gen_key in coho_gens.keys():
|
||||
gen = coho_gens[gen_key]
|
||||
found = False
|
||||
for i in range(1,dim):
|
||||
if (not found) and (i in dimensions):
|
||||
for j in range(i,dim):
|
||||
if (j in dimensions) and (i+j == dim):
|
||||
gensi = correspondence[i]
|
||||
gensj = correspondence[j]
|
||||
for gi in gensi.values():
|
||||
if not found:
|
||||
for gj in gensj.values():
|
||||
product = gi.cup_product(gj)
|
||||
if product == gen or -product == gen:
|
||||
found = True
|
||||
i_name = list(gensi.keys())[list(gensi.values()).index(gi)]
|
||||
j_name = list(gensj.keys())[list(gensj.values()).index(gj)]
|
||||
if gen_key in unmmaped_elements.keys():
|
||||
print("The element ",i_name+"*"+j_name," is already mapped")
|
||||
del unmmaped_elements[gen_key]
|
||||
break
|
||||
return unmmaped_elements
|
||||
|
||||
def surjective_step(A, M, phi, dim, names, degrees, differentials, cohomology_correspondence):
|
||||
|
||||
print("Surjectivity at dimension ", dim)
|
||||
coho_aplk = A.get_cohomology_aplk(dim)
|
||||
cohomology_gens = A.cohomology_gens(dim)
|
||||
g = get_unmapped_generators(dim, coho_aplk, cohomology_gens, cohomology_correspondence)
|
||||
new_names = copy.deepcopy(names)
|
||||
new_degrees = copy.deepcopy(degrees)
|
||||
new_phi = copy.deepcopy(phi)
|
||||
new_correspondence = copy.deepcopy(cohomology_correspondence)
|
||||
phi_n_map = {}
|
||||
correspondence_n_map = {}
|
||||
for gen_key in g.keys():
|
||||
deg = gen_key[0]
|
||||
index = gen_key[1]
|
||||
new_var = 'x'+str(deg)+'_'+str(index)
|
||||
new_names += [new_var]
|
||||
new_degrees += [deg]
|
||||
phi_n_map[new_var] = g[gen_key]
|
||||
correspondence_n_map[new_var] = cohomology_gens[gen_key]
|
||||
gca = GradedCommutativeAlgebra(QQ, names=new_names, degrees=new_degrees)
|
||||
new_M = update_cdga(gca, differentials)
|
||||
new_phi[dim] = phi_n_map
|
||||
new_correspondence[dim] = correspondence_n_map
|
||||
return [new_M, new_phi, new_names, new_degrees, new_correspondence]
|
||||
|
||||
def minimal_model(S, max_depth=5, max_dim=5):
|
||||
|
||||
fundamental_group = S.fundamental_group()
|
||||
if (fundamental_group.order() != 1):
|
||||
print("Warning: The space is not simply-connected")
|
||||
phi = {}
|
||||
cohomology_correspondence = {}
|
||||
A = AlgebraAplK(S)
|
||||
# First step of the algorithm
|
||||
first_dim = A.first_cohomology_group()
|
||||
phi_n_map = {}
|
||||
correspondence_n_map = {}
|
||||
if first_dim < 0:
|
||||
return [0,{},{}] # due to the function returns multiple objects
|
||||
elif first_dim > max_dim:
|
||||
return [0,{},{}] # due to the function returns multiple objects
|
||||
g = A.get_cohomology_aplk(first_dim)
|
||||
cohomology_gens = A.cohomology_gens(first_dim)
|
||||
names = []
|
||||
degrees = []
|
||||
for gen_key in g.keys():
|
||||
deg = gen_key[0]
|
||||
index = gen_key[1]
|
||||
new_var = 'x'+str(deg)+'_'+str(index)
|
||||
names += [new_var]
|
||||
degrees += [deg]
|
||||
phi_n_map[new_var] = g[gen_key]
|
||||
correspondence_n_map[new_var] = cohomology_gens[gen_key]
|
||||
differentials={}
|
||||
gca = GradedCommutativeAlgebra(QQ, names=names, degrees=degrees)
|
||||
M = gca.cdg_algebra(differentials)
|
||||
phi[first_dim] = phi_n_map
|
||||
cohomology_correspondence[first_dim] = correspondence_n_map
|
||||
# Now we have an isomorphism in the first non-null cohomology group
|
||||
# we check if phi is a monomorphism
|
||||
[M, phi, names, degrees, differentials, limit] = injectivity_step(M, phi, first_dim+1, names,
|
||||
degrees, differentials, index=0, depth=0, max_depth=5)
|
||||
if limit:
|
||||
print("The algorithm has reach the injectivity depth-limit at dimension ", first_dim)
|
||||
return [M, phi]
|
||||
else:
|
||||
dim = first_dim + 1
|
||||
for i in range(dim, max_dim):
|
||||
[M, phi, names, degrees, cohomology_correspondence] = surjective_step(A, M, phi, i, names, degrees,
|
||||
differentials, cohomology_correspondence)
|
||||
[M, phi, names, degrees, differentials, limit] = injectivity_step(M, phi, i+1, names,
|
||||
degrees, differentials, index=0, depth=0, max_depth=5)
|
||||
if limit:
|
||||
print("The algorithm has reach the injectivity depth-limit at dimension", dim)
|
||||
break
|
||||
|
||||
return [M, phi, cohomology_correspondence]
|
||||
|
||||
#######################################################
|
||||
# TESTS
|
||||
S1 = simplicial_complexes.Sphere(2)
|
||||
S2 = simplicial_complexes.Sphere(2)
|
||||
S = S1.wedge(S2, is_mutable=False)
|
||||
#######################################################
|
||||
#S = simplicial_complexes.ComplexProjectivePlane()
|
||||
#######################################################
|
||||
# S = simplicial_complexes.BrucknerGrunbaumSphere()
|
||||
#######################################################
|
||||
# S = simplicial_complexes.ProjectivePlane().wedge(simplicial_complexes.Sphere(2), is_mutable=False)
|
||||
#######################################################
|
||||
[sullivan_model, model_morphism, cohomology_correspondence] = minimal_model(S, max_depth=5, max_dim=10)
|
||||
sullivan_model
|
||||
|
||||
Loading…
Reference in New Issue
Block a user