Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ function free_resolution(::Type{T}, M::SubquoModule{RET}) where {T<:SimpleFreeRe
return result, aug_map_comp
end

function free_resolution(::Type{T}, F::FreeMod{RET}) where {T<:SimpleFreeResolution, RET}
ChainType = FreeMod{RET}
MorphismType = FreeModuleHom{ChainType, ChainType, Nothing}

M = SubquoModule(F, gens(F), elem_type(F)[])
chain_fac = ResolutionModuleFactory(M)
map_fac = ResolutionMapFactory{MorphismType}()

R = base_ring(M)
upper_bound = (R isa MPolyRing ? ngens(R) : nothing)
internal_complex = HyperComplex(1, chain_fac, map_fac, [:chain],
upper_bounds = [upper_bound],
lower_bounds = [0]
)
result = SimpleFreeResolution(M, internal_complex)
FC = ZeroDimensionalComplex(F)[0:0] # Wrap FC as a 1-dimensional complex concentrated in degree 0
aug_map = hom(result[(0,)], F, gens(F); check=false) # The actual augmentation map
aug_map.generators_map_to_generators = true
aug_map_comp = MorphismFromDict(result, FC, Dict{Tuple, typeof(aug_map)}([(0,)=>aug_map]))
result.augmentation_map = aug_map_comp
return result, aug_map_comp
end

function free_resolution(::Type{T}, I::Ideal{RET}) where {T<:SimpleFreeResolution, RET}
R = base_ring(I)
F = (!is_graded(R) ? FreeMod(R, 1) : graded_free_module(R, [zero(grading_group(R))]))
Expand Down
26 changes: 21 additions & 5 deletions experimental/DoubleAndHyperComplexes/src/Objects/induced_ENC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function (fac::InducedENCChainFactory)(self::AbsHyperComplex, ind::Tuple)
end
Ip, _ = sub(amb_ext_power, new_gens)
fac.ext_powers[i] = Ip
result = tensor_product(_symmetric_power(enc, i), Ip; ambient_tensor_product=enc[i])
result = tensor_product(_symmetric_power(enc, i), Ip)#; ambient_tensor_product=enc[i])
return result
end

Expand Down Expand Up @@ -62,11 +62,27 @@ function (fac::InducedENCMapFactory)(self::AbsHyperComplex, p::Int, I::Tuple)
# TODO: This can probably be sped up by lifting directly on the exterior powers.
img_gens = elem_type(cod)[]
ambient_map = map(enc, i)
@assert domain(ambient_map) === ambient_free_module(dom)
# The following does not hold anymore since the fix in #4810
#@assert domain(ambient_map) === ambient_free_module(dom)
decomp_dom = tensor_generator_decompose_function(dom)
pure_orig_dom = tensor_pure_function(domain(ambient_map))
decomp_orig_cod = tensor_generator_decompose_function(codomain(ambient_map))
cod_facs = get_attribute(cod, :tensor_product)::Tuple
pure_cod = tensor_pure_function(cod)

for g in gens(dom)
rep = repres(g)
image_g = ambient_map(rep)
push!(img_gens, cod(image_g))
img_gen = zero(cod)
for (i, c) in coordinates(g)
decomp_gen = decomp_dom(gen(dom, i))
v = Tuple([repres(a) for a in decomp_gen])
w = pure_orig_dom(v)
ww = ambient_map(w)
dec_img_rep = decomp_orig_cod(ww)
u = Tuple([cod_fac(b) for (cod_fac, b) in zip(cod_facs, dec_img_rep)])
uu = pure_cod(u)
img_gen += c*uu
end
push!(img_gens, img_gen)
end
return hom(dom, cod, img_gens)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ function (fac::HCTensorProductChainFactory{ChainType})(c::AbsHyperComplex, I::Tu
k = k + dim(f)
end
factors = [fac.factors[k][Tuple(a)] for (k, a) in enumerate(j)]
any(iszero, factors) && return zero_object(first(factors))[1]
#any(iszero, factors) && return zero_object(first(factors))[1]
tmp_res = _tensor_product(factors...)
@assert tmp_res isa Tuple{<:ChainType, <:Map} "the output of `tensor_product` does not have the anticipated format; see the source code for details"
# If you got here because of the error message above:
Expand Down
43 changes: 28 additions & 15 deletions src/Modules/UngradedModules/HomologicalAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,16 @@ function tensor_product(P::ModuleFP, C::Hecke.ComplexOfMorphisms{ModuleFP})
for i in 1:length(Hecke.map_range(C))
A = tensor_modules[i]
B = tensor_modules[i+1]

success, A_fac = _is_tensor_product(A)
@assert success
success, B_fac = _is_tensor_product(B)
@assert success
@assert A_fac[1] === B_fac[1]

j = Hecke.map_range(C)[i]
push!(tensor_chain, hom_tensor(A,B,[identity_map(P), map(C,j)]))
@assert domain(map(C, j)) === A_fac[2]
@assert codomain(map(C, j)) === B_fac[2]
push!(tensor_chain, hom_tensor(A,B,[identity_map(A_fac[1]), map(C,j)]))
end

return Hecke.ComplexOfMorphisms(ModuleFP, tensor_chain, seed=C.seed, typ=C.typ)
Expand Down Expand Up @@ -232,22 +239,28 @@ julia> Q, _ = quo(F, [x*F[1]]);

julia> T0 = tor(Q, M, 0)
Subquotient of submodule with 2 generators
1: x*e[1] \otimes e[1]
2: y*e[1] \otimes e[1]
by submodule with 4 generators
1: x^2*e[1] \otimes e[1]
2: y^3*e[1] \otimes e[1]
3: z^4*e[1] \otimes e[1]
4: x*y*e[1] \otimes e[1]
1: (e[1] \otimes e[1])
2: (e[1] \otimes e[2])
by submodule with 7 generators
1: x*(e[1] \otimes e[1])
2: -y*(e[1] \otimes e[1]) + x*(e[1] \otimes e[2])
3: y^2*(e[1] \otimes e[2])
4: y^3*(e[1] \otimes e[1])
5: z^4*(e[1] \otimes e[1])
6: z^4*(e[1] \otimes e[2])
7: x*(e[1] \otimes e[2])

julia> T1 = tor(Q, M, 1)
Subquotient of submodule with 2 generators
1: x*e[1] \otimes e[1]
2: x*y*e[1] \otimes e[1]
by submodule with 3 generators
1: x^2*e[1] \otimes e[1]
2: y^3*e[1] \otimes e[1]
3: z^4*e[1] \otimes e[1]
1: (e[1] \otimes e[1])
2: x*(e[1] \otimes e[2])
by submodule with 6 generators
1: x*(e[1] \otimes e[1])
2: -y*(e[1] \otimes e[1]) + x*(e[1] \otimes e[2])
3: y^2*(e[1] \otimes e[2])
4: y^3*(e[1] \otimes e[1])
5: z^4*(e[1] \otimes e[1])
6: z^4*(e[1] \otimes e[2])

julia> T2 = tor(Q, M, 2)
Submodule with 0 generators
Expand Down
81 changes: 35 additions & 46 deletions src/Modules/UngradedModules/Tensor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ function tensor_product(G::FreeMod...; task::Symbol = :none)
F.d = tensor_degrees
end

@assert _is_tensor_product(F)[1]
if task == :none
return F
end
Expand Down Expand Up @@ -103,72 +104,60 @@ julia> T, t = tensor_product(M, M; task = :map);

julia> gens(T)
4-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
x^2*e[1] \otimes e[1]
x*y*e[1] \otimes e[1]
x*y*e[1] \otimes e[1]
y^2*e[1] \otimes e[1]
(e[1] \otimes e[1])
(e[1] \otimes e[2])
(e[2] \otimes e[1])
(e[2] \otimes e[2])

julia> domain(t)
parent of tuples of type Tuple{SubquoModuleElem{QQMPolyRingElem}, SubquoModuleElem{QQMPolyRingElem}}

julia> t((M[1], M[2]))
x*y*e[1] \otimes e[1]
(e[1] \otimes e[2])
```
"""
function tensor_product(G::ModuleFP...;
ambient_tensor_product::FreeMod=tensor_product((ambient_free_module(x) for x in G)..., task = :none),
task::Symbol = :none
)
F = ambient_tensor_product
mF = tensor_pure_function(ambient_tensor_product)
# We want to store a dict where the keys are tuples of indices and the values
# are the corresponding pure vectors (i.e. a tuple (2,1,5) represents the
# 2nd, 1st and 5th generator of the 1st, 2nd and 3rd module, which we are
# tensoring. The corresponding value is then G[1][2] ⊗ G[2][1] ⊗ G[2][5]).
corresponding_tuples_as_indices = vec([x for x = Base.Iterators.ProductIterator(Tuple(1:ngens(x) for x = G))])
# In corresponding_tuples we store tuples of the actual generators, so in
# the example above we would store (G[1][2], G[2][1], G[2][5]).
corresponding_tuples = map(index_tuple -> Tuple(map(index -> G[index][index_tuple[index]],1:length(index_tuple))), corresponding_tuples_as_indices)

generating_tensors::Vector{elem_type(F)} = map(mF, map(tuple -> map(x -> parent(x) isa FreeMod ? x : repres(x), tuple), corresponding_tuples))
s, emb = sub(F, generating_tensors)
#s, emb = sub(F, vec([mF(x) for x = Base.Iterators.ProductIterator(Tuple(gens(x, ambient_free_module(x)) for x = G))]), :with_morphism)
q::Vector{elem_type(F)} = vcat([vec([mF(x) for x = Base.Iterators.ProductIterator(Tuple(i == j ? rels(G[i]) : gens(ambient_free_module(G[i])) for i=1:length(G)))]) for j=1:length(G)]...)
local projection_map
if length(q) != 0
s, projection_map = quo(s, q)
function tensor_product(G::ModuleFP...; task::Symbol = :none)
resols = AbsHyperComplex[]
augs = ModuleFPHom[]
for M in G
res, aug = free_resolution(SimpleFreeResolution, M)
push!(resols, res)
push!(augs, aug[0])
end

tuples_pure_tensors_dict = IdDict(zip(corresponding_tuples_as_indices, gens(s)))
set_attribute!(s, :show => Hecke.show_tensor_product, :tensor_product => G)

res_prod = tensor_product(resols)
tot = total_complex(res_prod)
pres = map(tot, 1)
I, inc_I = image(pres)
result, pr_res = quo(tot[0], I)

# assemble the multiplication and decomposition functions
z = Tuple([0 for _ in 1:length(G)])
@assert _is_tensor_product(res_prod[z])[1]
function pure(tuple_elems::Union{SubquoModuleElem,FreeModElem}...)
coeffs_tuples = vec([x for x in Base.Iterators.ProductIterator(coordinates.(tuple_elems))])
res = zero(s)
for coeffs_tuple in coeffs_tuples
indices = map(first, coeffs_tuple)
coeff_for_pure = prod(map(x -> x[2], coeffs_tuple))
res += coeff_for_pure*tuples_pure_tensors_dict[indices]
end
return res
w = [preimage(augs[i], x) for (i, x) in enumerate(tuple_elems)]
free_pure = tensor_pure_function(res_prod[z])
ww = free_pure(w...)
return pr_res(canonical_injection(tot[0], 1)(ww))
end
function pure(T::Tuple)
return pure(T...)
end

decompose_generator = function(v::SubquoModuleElem)
i = index_of_gen(v)
return corresponding_tuples[i]
w = canonical_projection(tot[0], 1)(preimage(pr_res, v))
w_dec = tensor_generator_decompose_function(res_prod[z])(w)
return Tuple([augs[i](x) for (i, x) in enumerate(w_dec)])
end

set_attribute!(s, :tensor_pure_function => pure, :tensor_generator_decompose_function => decompose_generator)

set_attribute!(result, :tensor_pure_function => pure, :tensor_generator_decompose_function => decompose_generator)
set_attribute!(result, :show => Hecke.show_tensor_product, :tensor_product => G)
@assert _is_tensor_product(result)[1]

if task == :none
return s
return result
end

return s, MapFromFunc(Hecke.TupleParent(Tuple([zero(g) for g = G])), s, pure, decompose_generator)
return result, MapFromFunc(Hecke.TupleParent(Tuple([zero(g) for g = G])), result, pure, decompose_generator)
end


3 changes: 1 addition & 2 deletions test/Modules/ModulesGraded.jl
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ end
M = SubquoModule(F, A, B)
free_res = free_resolution_via_kernels(M)
F1 = graded_free_module(Rg, 1)
N = SubquoModule(F1, Rg[x+2*x^2*z; x+y-z], Rg[z^4;])
N = SubquoModule(F1, Rg[x^3+2*x^2*z; x+y-z], Rg[z^4;])
tensor_resolution = tensor_product(free_res,N)
@test chain_range(tensor_resolution) == chain_range(free_res)
for i in Hecke.map_range(tensor_resolution)
Expand Down Expand Up @@ -710,7 +710,6 @@ end
T0 = tor(Q, M, 0)
T1 = tor(Q, M, 1)
T2 = tor(Q, M, 2)
@test is_canonically_isomorphic(T0, M)
@test ngens(present_as_cokernel(T1)) == ngens(M_coker)
# Todo twist
@test iszero(T2)
Expand Down
Loading
Loading