244 lines
9.9 KiB
Python
244 lines
9.9 KiB
Python
r"""
|
|
<Short one-line summary that ends with no period>
|
|
|
|
<Paragraph description>
|
|
|
|
EXAMPLES::
|
|
|
|
<Lots and lots of examples>
|
|
|
|
AUTHORS:
|
|
|
|
- Carlos Alquézar Baeta (2023-02-07): initial version
|
|
- Miguel Ángel Marco (2023-02-07): initial version
|
|
- Jorge Martín Morales (2023-02-07): initial version
|
|
|
|
"""
|
|
|
|
# ****************************************************************************
|
|
# Copyright (C) 2023 Carlos Alquézar Baeta <alquezar@unizar.es>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
# https://www.gnu.org/licenses/
|
|
# ****************************************************************************
|
|
|
|
def phi_polinomial(pol, model_morphism, A):
|
|
#pol_keys = pol.dict().keys()
|
|
m_gens = pol.parent().gens()
|
|
#m_gens = [g for g,e in zip(gens,sum([vector(k) for k in pol_keys])) if e]
|
|
aplkGens = {g: model_morphism[g.degree()][str(g)] for g in m_gens}
|
|
aplkElement = A.null_element()
|
|
for exp in pol.dict().keys():
|
|
coef = pol.dict()[exp]
|
|
# To-Do: check if exp and aplkGens are sorted in the same way
|
|
term = coef*A.one()
|
|
for i in range(len(exp)):
|
|
e = exp[i]
|
|
if e:
|
|
aGen = aplkGens[m_gens[i]]
|
|
term *= aGen**e
|
|
#term = coef*prod([gen^e for (gen,e) in zip(aplkGens, exp)])
|
|
aplkElement += term
|
|
return aplkElement
|
|
|
|
|
|
def get_ker_elements(sullivan_model, model_morphism, A, dim):
|
|
# Get the basis of Hm
|
|
hm_basis = sullivan_model.cohomology(dim).basis()
|
|
if hm_basis:
|
|
Hc = A.cohomology_group(dim)
|
|
apl_correspondence = {}
|
|
cochain_correspondence = {}
|
|
Hc_correspondence = {}
|
|
M = zero_matrix(QQ, len(Hc.basis()), len(hm_basis))
|
|
i = 0
|
|
hm_basis_keys = [g.representative() for g in hm_basis.keys()]
|
|
for gen_repr in hm_basis_keys:
|
|
# get an element of the basis of Hm
|
|
# get a representative of a cohomology class in M
|
|
# get the apl representative for each generator of M^p
|
|
apl_correspondence[gen_repr] = phi_polinomial(
|
|
gen_repr, model_morphism, A)
|
|
cochain = apl_correspondence[gen_repr].integral()
|
|
cochain_correspondence[gen_repr] = cochain
|
|
vcochain = A.cochain_to_vector(cochain, dim)
|
|
Hc_correspondence[gen_repr] = Hc(vcochain)
|
|
M[:, i] = Hc_correspondence[gen_repr]
|
|
i += 1
|
|
kernelGens = M.right_kernel().basis()
|
|
m_kernel = [sum([a*b for a, b in zip(hm_basis_keys, g)])
|
|
for g in kernelGens]
|
|
return m_kernel
|
|
else:
|
|
return []
|
|
|
|
|
|
def convert_to(element, gca):
|
|
d = element.dict()
|
|
new_e = {tuple(list(k)+[0]): d[k] for k in d.keys()}
|
|
return gca(new_e)
|
|
|
|
|
|
def injectivity_step(M, phi, check_dim, names,
|
|
degrees, differentials, A, index=0, depth=0, max_depth=5):
|
|
|
|
print("Injectivity at dimension ", check_dim)
|
|
if depth > max_depth:
|
|
return [M, phi, names, degrees, differentials, True]
|
|
new_M = M
|
|
new_phi = phi
|
|
new_names = names
|
|
new_degrees = degrees
|
|
new_differentials = differentials
|
|
m_kernel = get_ker_elements(M, phi, A, check_dim)
|
|
if len(m_kernel) > 0:
|
|
phi_new_gen = {}
|
|
for kerElement in m_kernel:
|
|
new_gen = 'y'+str(check_dim-1)+'_'+str(index)
|
|
print(" Proceed to kill", kerElement,
|
|
" because has associated trivial cohomology class")
|
|
print("Adding generator "+new_gen)
|
|
new_names = names + [new_gen]
|
|
new_degrees = tuple(list(degrees)+[check_dim-1])
|
|
gca = GradedCommutativeAlgebra(
|
|
QQ, names=new_names, degrees=new_degrees)
|
|
gen = gca.gens_dict()[new_gen]
|
|
aplkElement = phi_polinomial(kerElement, phi, A)
|
|
if aplkElement == A.null_element():
|
|
preimage = A.null_element()
|
|
else:
|
|
preimage = aplkElement.solve_primitive()
|
|
phi_new_gen = {str(gen): preimage}
|
|
new_differentials = {convert_to(k, gca): convert_to(
|
|
differentials[k], gca) for k in differentials.keys()}
|
|
new_differentials.update({gen: convert_to(kerElement, gca)})
|
|
new_M = gca.cdg_algebra(new_differentials)
|
|
new_phi = {k: {s: phi[k][s]
|
|
for s in phi[k].keys()} for k in phi.keys()}
|
|
d = new_phi[check_dim-1]
|
|
d.update(phi_new_gen)
|
|
return injectivity_step(new_M, new_phi, check_dim, new_names,
|
|
new_degrees, new_differentials, A, index=index+1, depth=depth+1, max_depth=max_depth)
|
|
else:
|
|
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 = 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 = deepcopy(names)
|
|
new_degrees = deepcopy(degrees)
|
|
new_phi = {k: {s: phi[k][s] for s in phi[k].keys()} for k in phi.keys()}
|
|
new_correspondence = 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 = gca.cdg_algebra(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, A, 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):
|
|
print("phi")
|
|
print(phi)
|
|
[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, A, 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]
|