From 7cf97ad52c0f10d5ca36b25ebb250544a5d098c9 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Thu, 5 Jan 2023 16:36:29 +0100 Subject: [PATCH 01/14] Address changes requested on GH. --- experimental/Schemes/Sheaves.jl | 27 +++------------------------ experimental/Schemes/Types.jl | 16 ++++++---------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index 82334dd8b699..be83fd65132b 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -174,7 +174,7 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) === ambient_scheme(V) in the basic charts of X # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) != ambient_scheme(V) both in the basic charts of X # and U and V contained in the glueing domains of their ambient schemes - # * U::AbsSpec ⊂ U::AbsSpec in the basic charts of X + # * U::AbsSpec ⊂ V::AbsSpec in the basic charts of X # * U::AbsSpec ⊂ X for U in the basic charts # * U::PrincipalOpenSubset ⊂ X with ambient_scheme(U) in the basic charts of X # * W::SpecOpen ⊂ X with ambient_scheme(U) in the basic charts of X @@ -188,14 +188,6 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) B = ambient_scheme(codomain(inc_V_flat)) Udirect = codomain(inc_U_flat) Vdirect = codomain(inc_V_flat) - # some_ancestor(W->any(WW->(WW===W), affine_charts(X)), U) || return false - # some_ancestor(W->any(WW->(WW===W), affine_charts(X)), V) || return false - # incU, dU = _find_chart(U, default_covering(X)) - # incV, dU = _find_chart(V, default_covering(X)) - # A = codomain(incU) - # B = codomain(incV) - # Udirect = (ambient_scheme(U) === A ? U : PrincipalOpenSubset(codomain(incU), dU)) - # Vdirect = (ambient_scheme(V) === B ? V : PrincipalOpenSubset(codomain(incV), dV)) if A === B is_subset(Udirect, Vdirect) || return false @@ -212,11 +204,12 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, Y::AbsCoveredScheme ) - return Y === X && some_ancestor(W->(W in affine_charts(X)), U) + return Y === X && some_ancestor(W->(any(WW->(WW == W, affine_charts(X)))), U) end function is_open_func(U::AbsSpec, Y::AbsCoveredScheme) return Y === X && some_ancestor(W->any(WW->(WW===W), affine_charts(X)), U) end + # The following is implemented for the sake of completeness for boundary cases. function is_open_func(Z::AbsCoveredScheme, Y::AbsCoveredScheme) return X === Y === Z end @@ -235,12 +228,8 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) A = ambient_scheme(codomain(inc_U_flat)) Udirect = codomain(inc_U_flat) W = ambient_scheme(Udirect) - # some_ancestor(W->(W===V), U) && return true - # incU, dU = _find_chart(U, default_covering(X)) - # W = codomain(incU) haskey(glueings(default_covering(X)), (W, V)) || return false # In this case, they are not glued G = default_covering(X)[W, V] - #Udirect = (ambient_scheme(U) === W ? U : PrincipalOpenSubset(W, dU)) return is_subset(Udirect, glueing_domains(G)[1]) end function is_open_func(W::SpecOpen, Y::AbsCoveredScheme) @@ -263,14 +252,10 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) inc_V_flat = _flatten_open_subscheme(V, default_covering(X)) Vdirect = codomain(inc_V_flat) PV = ambient_scheme(Vdirect) - #incV, dV = _find_chart(V, default_covering(X)) - #Vdirect = PrincipalOpenSubset(codomain(incV), dV) - #PV = codomain(incV) PW in default_covering(X) || return false PV in default_covering(X) || return false if PW === PV return issubset(W, V) - #return all(x->(issubset(x, V)), affine_patches(W)) else haskey(glueings(default_covering(X)), (PW, PV)) || return false G = default_covering(X)[PW, PV] @@ -285,7 +270,6 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) PV in default_covering(X) || return false if PW === PV return issubset(W, V) - #return all(x->(issubset(x, V)), affine_patches(W)) else G = default_covering(X)[PW, PV] preV = preimage(glueing_morphisms(G)[1], V) @@ -312,16 +296,11 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) inc_U_flat = _flatten_open_subscheme(U, default_covering(X)) A = ambient_scheme(codomain(inc_U_flat)) Udirect = codomain(inc_U_flat) - #some_ancestor(W->any(WW->(WW===W), affine_charts(X)), U) - #incU, dU = _find_chart(U, default_covering(X)) - #U_direct = PrincipalOpenSubset(codomain(incU), dU) - #ambient_scheme(U) in default_covering(X) || return false U_flat = codomain(inc_U_flat) PU = ambient_scheme(U_flat) if PU === ambient_scheme(W) # in this case W must be equal to U return issubset(W, U_flat) - #return one(OO(U)) in complement_ideal(W) else G = default_covering(X)[ambient_scheme(W), PU] issubset(U_flat, glueing_domains(G)[2]) || return false diff --git a/experimental/Schemes/Types.jl b/experimental/Schemes/Types.jl index 25b3bcd3e577..2697a3914f15 100644 --- a/experimental/Schemes/Types.jl +++ b/experimental/Schemes/Types.jl @@ -425,7 +425,9 @@ identifications given by the glueings in the `default_covering`. V_direct = PrincipalOpenSubset(W, dV) if W === U return pullback(inverse(incV)) - ### deprecated code below + ### deprecated code below; + # kept for the moment because of possible incompatibilities with glueings + # along SpecOpens. function rho_func(a::RingElem) parent(a) === OV || error("element does not belong to the correct ring") # We may assume that all denominators admissible in V are @@ -440,7 +442,7 @@ identifications given by the glueings in the `default_covering`. g_res = restrict(g, U, V_direct) inc_res = restrict(incV, V, V_direct, check=false) return pullback(compose(g_res, inverse(inc_res))) - ### deprecated code below + ### deprecated code below; see comment above function rho_func2(a::RingElem) parent(a) === OV || error("element does not belong to the correct ring") return restrict(pullback(g)(OO(W1)(a)), U) @@ -460,14 +462,6 @@ identifications given by the glueings in the `default_covering`. B = ambient_scheme(codomain(inc_V_flat)) U_flat = codomain(inc_U_flat) V_flat = codomain(inc_V_flat) - # incV, dV = _find_chart(V, default_covering(X)) - # incU, dU = _find_chart(U, default_covering(X)) - # A = codomain(incV) - # B = codomain(incU) - # V_direct = PrincipalOpenSubset(A, dV) - # incV_res = restrict(incV, V, V_direct) - # U_direct = PrincipalOpenSubset(B, dU) - # incU_res = restrict(incU, U, U_direct) if A === B return hom(OV, OU, @@ -512,6 +506,8 @@ identifications given by the glueings in the `default_covering`. end ### cleaned up until here ### + # We do not make SpecOpen compatible with the tree structures, yet. + # All SpecOpen's are hence required to have an ambient_scheme on the top level. function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, W::SpecOpen) error("method not implemented at the moment") From 92ebcaf997553aeed28437bc090bea9af7402f3e Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Thu, 5 Jan 2023 16:46:21 +0100 Subject: [PATCH 02/14] clean up ideal sheaves. --- experimental/Schemes/Sheaves.jl | 73 ++++++++++++++++++++++++++++++++- experimental/Schemes/Types.jl | 64 +++++------------------------ 2 files changed, 82 insertions(+), 55 deletions(-) diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index be83fd65132b..7dd9c61ef844 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -204,7 +204,7 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, Y::AbsCoveredScheme ) - return Y === X && some_ancestor(W->(any(WW->(WW == W, affine_charts(X)))), U) + return Y === X && some_ancestor(W->(any(WW->(WW === W), affine_charts(X))), U) end function is_open_func(U::AbsSpec, Y::AbsCoveredScheme) return Y === X && some_ancestor(W->any(WW->(WW===W), affine_charts(X)), U) @@ -309,6 +309,77 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) end end + return is_open_func +end + +function _is_open_func_for_schemes_without_specopen(X::AbsCoveredScheme) + ### Checks for open containment. + # + # We allow the following cases: + # + # * U::PrincipalOpenSubset with one ancestor W in the basic charts of X + # * U::SimplifiedSpec with one ancestor W in the basic charts of X + # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) === ambient_scheme(V) in the basic charts of X + # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) != ambient_scheme(V) both in the basic charts of X + # and U and V contained in the glueing domains of their ambient schemes + # * U::AbsSpec ⊂ V::AbsSpec in the basic charts of X + # * U::AbsSpec ⊂ X for U in the basic charts + # * U::PrincipalOpenSubset ⊂ X with ambient_scheme(U) in the basic charts of X + function is_open_func( + U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, + V::Union{<:PrincipalOpenSubset, <:SimplifiedSpec} + ) + inc_U_flat = _flatten_open_subscheme(U, default_covering(X)) + inc_V_flat = _flatten_open_subscheme(V, default_covering(X)) + A = ambient_scheme(codomain(inc_U_flat)) + B = ambient_scheme(codomain(inc_V_flat)) + Udirect = codomain(inc_U_flat) + Vdirect = codomain(inc_V_flat) + + if A === B + is_subset(Udirect, Vdirect) || return false + else + G = default_covering(X)[A, B] # Get the glueing + f, g = glueing_morphisms(G) + is_subset(Udirect, domain(f)) || return false + gU = preimage(g, Udirect) + is_subset(gU, Vdirect) || return false + end + return true + end + function is_open_func( + U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, + Y::AbsCoveredScheme + ) + return Y === X && some_ancestor(W->(any(WW->(WW === W), affine_charts(X))), U) + end + function is_open_func(U::AbsSpec, Y::AbsCoveredScheme) + return Y === X && some_ancestor(W->any(WW->(WW===W), affine_charts(X)), U) + end + # The following is implemented for the sake of completeness for boundary cases. + function is_open_func(Z::AbsCoveredScheme, Y::AbsCoveredScheme) + return X === Y === Z + end + function is_open_func(U::AbsSpec, V::AbsSpec) + U in affine_charts(X) || return false + V in affine_charts(X) || return false + G = default_covering(X)[U, V] + return issubset(U, glueing_domains(G)[1]) + end + function is_open_func( + U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, + V::AbsSpec + ) + V in affine_charts(X) || return false + inc_U_flat = _flatten_open_subscheme(U, default_covering(X)) + A = ambient_scheme(codomain(inc_U_flat)) + Udirect = codomain(inc_U_flat) + W = ambient_scheme(Udirect) + haskey(glueings(default_covering(X)), (W, V)) || return false # In this case, they are not glued + G = default_covering(X)[W, V] + return is_subset(Udirect, glueing_domains(G)[1]) + end + return is_open_func end underlying_presheaf(S::StructureSheafOfRings) = S.OO diff --git a/experimental/Schemes/Types.jl b/experimental/Schemes/Types.jl index 2697a3914f15..61fd9cd7646d 100644 --- a/experimental/Schemes/Types.jl +++ b/experimental/Schemes/Types.jl @@ -593,59 +593,6 @@ identifications given by the glueings in the `default_covering`. ) OOX = StructureSheafOfRings(X) - ### Checks for open containment. - # - # We allow the following cases: - # - # * U::PrincipalOpenSubset in W===ambient_scheme(U) in the basic charts of X - # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) === ambient_scheme(V) in the basic charts of X - # * U::PrincipalOpenSubset ⊂ V::PrincipalOpenSubset with ambient_scheme(U) != ambient_scheme(V) both in the basic charts of X - # and U and V contained in the glueing domains of their ambient schemes - # * U::AbsSpec ⊂ U::AbsSpec in the basic charts of X - # * U::AbsSpec ⊂ X for U in the basic charts - # * U::PrincipalOpenSubset ⊂ X with ambient_scheme(U) in the basic charts of X - function is_open_func(U::PrincipalOpenSubset, V::PrincipalOpenSubset) - C = default_covering(X) - A = ambient_scheme(U) - A in C || return false - B = ambient_scheme(V) - B in C || return false - if A === B - is_subset(U, V) || return false - else - G = C[A, B] # Get the glueing - f, g = glueing_morphisms(G) - is_subset(U, domain(f)) || return false - is_subset(V, domain(g)) || return false - gU = preimage(g, U) - is_subset(gU, V) || return false - end - return true - end - function is_open_func(U::PrincipalOpenSubset, Y::AbsCoveredScheme) - return Y === X && ambient_scheme(U) in default_covering(X) - end - function is_open_func(U::AbsSpec, Y::AbsCoveredScheme) - return Y === X && U in default_covering(X) - end - function is_open_func(Z::AbsCoveredScheme, Y::AbsCoveredScheme) - return X === Y === Z - end - function is_open_func(U::AbsSpec, V::AbsSpec) - U in default_covering(X) || return false - V in default_covering(X) || return false - G = default_covering(X)[U, V] - return issubset(U, glueing_domains(G)[1]) - end - function is_open_func(U::PrincipalOpenSubset, V::AbsSpec) - V in default_covering(X) || return false - ambient_scheme(U) === V && return true - W = ambient_scheme(U) - W in default_covering(X) || return false - G = default_covering(X)[W, V] - return is_subset(U, glueing_domains(G)[1]) - end - ### Production of the rings of regular functions; to be cached function production_func(F::AbsPreSheaf, U::AbsSpec) # If U is an affine chart on which the ideal has already been described, take that. @@ -669,12 +616,21 @@ identifications given by the glueings in the `default_covering`. return ideal(OO(U), one(OO(U))) end function production_func(F::AbsPreSheaf, U::PrincipalOpenSubset) + haskey(ID, U) && return ID[U] V = ambient_scheme(U) IV = F(V)::Ideal rho = OOX(V, U) IU = ideal(OO(U), rho.(gens(IV))) return IU end + function production_func(F::AbsPreSheaf, U::SimplifiedSpec) + haskey(ID, U) && return ID[U] + V = original(U) + IV = F(V)::Ideal + rho = OOX(V, U) + IU = ideal(OO(U), rho.(gens(IV))) + return IU + end ### Production of the restriction maps; to be cached function restriction_func(F::AbsPreSheaf, V::AbsSpec, U::AbsSpec) @@ -686,7 +642,7 @@ identifications given by the glueings in the `default_covering`. Ipre = PreSheafOnScheme(X, production_func, restriction_func, OpenType=AbsSpec, OutputType=Ideal, RestrictionType=Hecke.Map, - is_open_func=is_open_func + is_open_func=_is_open_func_for_schemes_without_specopen(X) ) I = new{typeof(X), AbsSpec, Ideal, Hecke.Map}(ID, OOX, Ipre) if check From 17377a98bf6f50dbfe454f3873d6dbc8209efe91 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Thu, 5 Jan 2023 20:39:58 +0100 Subject: [PATCH 03/14] First round cleaning up restrictions of coherent sheaves. --- experimental/Schemes/CoherentSheaves.jl | 169 +++++++++++++++++++++--- experimental/Schemes/SimplifiedSpec.jl | 90 ++++++++++++- test/Schemes/CoherentSheaves.jl | 6 + 3 files changed, 249 insertions(+), 16 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 9984c1b4659c..365518434422 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -164,23 +164,162 @@ identifications given by the glueings in the `default_covering`. ### Production of the restriction maps; to be cached function restriction_func(F::AbsPreSheaf, V::AbsSpec, U::AbsSpec) - MV = F(V) - MU = F(U) - # There are two cases: Either U is a PrincipalOpenSubset of V, or U - # is a PrincipalOpenSubset of another affine_chart W. In both cases, - # we need to find W (which equals V in the first case) and use the transition - # matrix for the changes between these two sets. - VV = V - while VV isa PrincipalOpenSubset - VV = ambient_scheme(VV) + if any(W->(W === U), affine_charts(X)) && any(W->(W === V), affine_charts(X)) + MV = F(V) + MU = F(U) + A = MG[(V, U)] # The transition matrix + UU, _ = glueing_domains(default_covering(X)[U, V]) + psi = OOX(UU, U) # Needs to exist by the checks of is_open_func, even though + # in general UU ⊂ U! + return hom(MV, MU, [sum([psi(A[i, j]) * MU[j] for j in 1:ngens(MU)]) for i in 1:ngens(MV)], rho) + else + error("invalid input") end - UU = U - while UU isa PrincipalOpenSubset - UU = ambient_scheme(UU) + end + + function restriction_func(F::AbsPreSheaf, V::AbsSpec, U::PrincipalOpenSubset) + # If V was not an affine_chart of X, some other function would have + # been triggered. + + # First the easy case: Inheritance from an ancestor in the tree. + if ambient_scheme(U) === V + # If the restriction was more complicated than what follows, then + # it would have been cached earlier and this call would not have happened + # This is the end of the recursion induced in the next elseif below. + W = ambient_scheme(U) + res = hom(F(W), F(U), gens(MU), OOX(W, U)) + return res + elseif some_ancestor(W->(W === V), U) + W = ambient_scheme(U) + return compose(F(V, W), F(W, U)) + end + + # Now we know we have a transition across charts + W = __find_chart(U, default_covering(X)) + A = MG[(V, W)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[W, V]) + # From W to U (and hence also from WW to U) the generators of the modules + # in F might have changed. Thus, we have to expect a non-trivial transition + # from the top-level down to U. The transition matrix A is only given with + # respect to the generators of F(W), so we have to map them manually down. + # The call to F(W, U) will be handled by the above if-clauses. + return hom(F(V), F(U), + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))]) + for i in 1:ngens(F(V))], + OOX(V, U) + ) + end + + function restriction_func(F::AbsPreSheaf, V::AbsSpec, U::SimplifiedSpec) + # If V was not an affine_chart of X, some other function would have + # been triggered. + + # First the easy case: Inheritance from an ancestor in the tree. + if original(U) === V + # If the restriction was more complicated than what follows, then + # it would have been cached earlier and this call would not have happened + # This is the end of the recursion induced in the next elseif below. + W = original(U) + res = hom(F(W), F(U), gens(MU), OOX(W, U)) + return res + elseif some_ancestor(W->(W === V), U) + W = original(U) + return compose(F(V, W), F(W, U)) end - rho = OOX(V, U) - A = MG[(VV, UU)] # The transition matrix - return hom(MV, MU, [sum([A[i, j] * MU[j] for j in 1:ngens(MU)]) for i in 1:ngens(MV)], rho) + + # Now we know we have a transition across charts + W = __find_chart(U, default_covering(X)) + A = MG[(V, W)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[W, V]) + # From W to U (and hence also from WW to U) the generators of the modules + # in F might have changed. Thus, we have to expect a non-trivial transition + # from the top-level down to U. The transition matrix A is only given with + # respect to the generators of F(W), so we have to map them manually down. + # The call to F(W, U) will be handled by the above if-clauses. + return hom(F(V), F(U), + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))]) + for i in 1:ngens(F(V))], + OOX(V, U) + ) + end + function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::AbsSpec) + # Problem: We can assume that we know how to pass from generators + # of W = __find_chart(V, default_covering(X)) to those on V, but we do not + # know the inverse to this. But the transition matrix to U is given + # with respect to the generators on W. + error("case not implemented") + end + function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::PrincipalOpenSubset) + V === U && return identity_map(F(U)) + + if V === ambient_scheme(U) + return hom(F(V), F(U), gens(F(U)), OOX(V, U)) # If this had been more complicated, it would have been cached. + elseif some_ancestor(W->W===V, U) + W = ambient_scheme(U) + return compose(F(V, W), F(W, U)) + end + + # Below follow the more complicated cases. + success, _ = _have_common_ancestor(U, V) + if success + W = __find_chart(U, default_covering(X)) + gens_U = F(W, U).(gens(F(W))) # This will be caught by the preceeding clauses + gens_V = F(W, V).(gens(F(W))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(OOX(V, U)(c[i])*gens_U[i] + for i in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + end + + # Now we know we have a transition between different charts. + inc_U = _flatten_open_subscheme(U, default_covering(X)) + inc_V = _flatten_open_subscheme(V, default_covering(X)) + U_flat = codomain(inc_U) + V_flat = codomain(inc_V) + WU = ambient_scheme(U_flat) + WV = ambient_scheme(V_flat) + WU = __find_chart(U, default_covering(X)) + WV = __find_chart(V, default_covering(X)) + # The problem is: The generators of F(WU) may be different from + # those of F(U) and similarly for V. But the transition matrices + # are only described for those on WU and WV. Thus we need to + # implicitly do a base change. This is done by forwarding the generators + # of F(WU) to F(U) and expressing it in terms of the generators there. + gens_U = F(WU, U).(gens(F(WU))) # This will be caught by the preceeding clauses + gens_V = F(WV, V).(gens(F(WV))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + A = MG[(WV, WU)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[WU, WV]) + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(sum(OOX(V, U)(c[i])*OOX(WW, U)(A[i, j])*gens_U[j] + for i in 1:length(gens_V)) + for j in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + end + function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::SimplifiedSpec) + error("case not implemented") + end + function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::AbsSpec) + error("case not implemented") + end + function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::PrincipalOpenSubset) + error("case not implemented") + end + function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::SimplifiedSpec) + error("case not implemented") end Mpre = PreSheafOnScheme(X, production_func, restriction_func, diff --git a/experimental/Schemes/SimplifiedSpec.jl b/experimental/Schemes/SimplifiedSpec.jl index 549f8bbb4fe9..59dcbfb99e02 100644 --- a/experimental/Schemes/SimplifiedSpec.jl +++ b/experimental/Schemes/SimplifiedSpec.jl @@ -87,6 +87,21 @@ function _find_chart(U::SimplifiedSpec, C::Covering; return compose(f, h), d end +function __find_chart(U::AbsSpec, C::Covering) + any(W->(W === U), patches(C)) || error("patch not found") + return U +end + +function __find_chart(U::PrincipalOpenSubset, C::Covering) + any(W->(W === U), patches(C)) && return U + return __find_chart(ambient_scheme(U), C) +end + +function __find_chart(U::SimplifiedSpec, C::Covering) + any(W->(W === U), patches(C)) && return U + return __find_chart(original(U), C) +end + #= # This follows U in its ancestor tree up to the point # where a patch W in C is found. Then it recreates U as a @@ -156,4 +171,77 @@ function _flatten_open_subscheme( return _flatten_open_subscheme(W, C, iso=new_iso) end - +######################################################################## +# Lookup of common ancestors # +# # +# This returns the node in the natural tree structure which is closest # +# to the two input schemes. # +######################################################################## +function _have_common_ancestor(U::PrincipalOpenSubset, V::PrincipalOpenSubset) + U === V && return true + if ambient_scheme(U) === V + return true, V + elseif ambient_scheme(V) === U + return true, U + elseif ambient_scheme(V) === ambient_scheme(U) + return true, ambient_scheme(V) + end + return _have_common_ancestor(ambient_scheme(U), ambient_scheme(V)) +end + +function _have_common_ancestor(U::AbsSpec, V::PrincipalOpenSubset) + return _have_common_ancestor(U, ambient_scheme(V)) +end + +function _have_common_ancestor( + V::PrincipalOpenSubset, + U::AbsSpec + ) + return _have_common_ancestor(U, ambient_scheme(V)) +end + +function _have_common_ancestor(U::AbsSpec, V::AbsSpec) + return U===V, U +end + +function _have_common_ancestor(U::AbsSpec, V::SimplifiedSpec) + return _have_common_ancestor(U, original(V)) +end + +function _have_common_ancestor( + V::SimplifiedSpec, + U::AbsSpec + ) + return _have_common_ancestor(U, original(V)) +end + +function _have_common_ancestor(U::PrincipalOpenSubset, V::SimplifiedSpec) + U === V && return true + if ambient_scheme(U) === V + return true, V + elseif original(V) === U + return true, U + elseif original(V) === ambient_scheme(U) + return true, original(V) + end + return _have_common_ancestor(ambient_scheme(U), original(V)) +end + +function _have_common_ancestor( + V::SimplifiedSpec, + U::PrincipalOpenSubset + ) + return _have_common_ancestor(U, V) +end + +function _have_common_ancestor(U::SimplifiedSpec, V::SimplifiedSpec) + U === V && return true + if original(U) === V + return true, V + elseif original(V) === U + return true, U + elseif original(V) === original(U) + return true, original(V) + end + return _have_common_ancestor(original(U), original(V)) +end diff --git a/test/Schemes/CoherentSheaves.jl b/test/Schemes/CoherentSheaves.jl index 6de532cc3857..c84800a420a8 100644 --- a/test/Schemes/CoherentSheaves.jl +++ b/test/Schemes/CoherentSheaves.jl @@ -23,6 +23,12 @@ @test g in T(U21) @test element_to_homomorphism(g)(domain(T)(U21)[1]) in codomain(T)(U21) + simplify!(X) + CC = coverings(X)[2] + for U in patches(CC) + @test_broken !iszero(T(U)) + end + HomM1M1 = oscar.HomSheaf(M1, M1) rho = HomM1M1(U[1], U21) g = HomM1M1(U[1])[1] From 2a553598af5085480f7631e66618ccec6ecb6376 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Fri, 6 Jan 2023 13:29:01 +0100 Subject: [PATCH 04/14] Small fix in the modules. --- src/Modules/UngradedModules.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/UngradedModules.jl b/src/Modules/UngradedModules.jl index 4c9e93344ad9..39314936bd79 100644 --- a/src/Modules/UngradedModules.jl +++ b/src/Modules/UngradedModules.jl @@ -6785,7 +6785,7 @@ function change_base_ring(f::Hecke.Map{DomType, CodType}, M::SubQuo) where {DomT S = codomain(f) F = ambient_free_module(M) R = base_ring(M) - FS, mapF = change_base_ring(S, F) + FS, mapF = change_base_ring(f, F) g = ambient_representatives_generators(M) rels = relations(M) MS = SubQuo(FS, mapF.(g), mapF.(rels)) From 4045fd9e3d00bc28cdc335b59ebb753a5aa650df Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Fri, 6 Jan 2023 13:29:17 +0100 Subject: [PATCH 05/14] Fix tests. --- experimental/Schemes/CoherentSheaves.jl | 44 +++++++++++++++++++++++-- test/Schemes/CoherentSheaves.jl | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 365518434422..5bd6d3a307d6 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -150,6 +150,7 @@ identifications given by the glueings in the `default_covering`. haskey(MD, U) && return MD[U] error("module on $U was not found") end + function production_func( F::AbsPreSheaf, U::PrincipalOpenSubset @@ -162,6 +163,18 @@ identifications given by the glueings in the `default_covering`. return MU end + function production_func( + F::AbsPreSheaf, + U::SimplifiedSpec + ) + V = original(U) + MV = F(V) + rho = OOX(V, U) + MU, phi = change_base_ring(rho, MV) + add_incoming_restriction!(F, V, MU, phi) + return MU + end + ### Production of the restriction maps; to be cached function restriction_func(F::AbsPreSheaf, V::AbsSpec, U::AbsSpec) if any(W->(W === U), affine_charts(X)) && any(W->(W === V), affine_charts(X)) @@ -243,6 +256,29 @@ identifications given by the glueings in the `default_covering`. ) end function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::AbsSpec) + # We know that V can not be an ancestor of U, but U must be an affine chart. + # Probably even an ancestor of V itself. + W = __find_chart(V, default_covering(X)) + if W === U + # U and V must actually be isomorphic, but the modules of F might be + # represented in different ways. We have to construct the inverse of + # the restriction map from U to V. + gens_U = F(U, V).(gens(F(U))) + M, inc = sub(F(V), gens_U) + img_gens = elem_type(F(U))[] + for v in gens(F(V)) + w = preimage(inc, v) + c = coordinates(w) + push!(img_gens, + sum(OOX(V, U)(c[i])*gens(F(U), i) for i in 1:ngens(F(U))) + ) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + else + # U must be properly contained in the glueing domains of the + # glueing of the affine chart of V with U. + error("case not implemented") + end # Problem: We can assume that we know how to pass from generators # of W = __find_chart(V, default_covering(X)) to those on V, but we do not # know the inverse to this. But the transition matrix to U is given @@ -325,7 +361,8 @@ identifications given by the glueings in the `default_covering`. Mpre = PreSheafOnScheme(X, production_func, restriction_func, OpenType=AbsSpec, OutputType=ModuleFP, RestrictionType=Hecke.Map, - is_open_func=_is_open_for_modules(X) + is_open_func=_is_open_func_for_schemes_without_specopen(X) + #is_open_func=_is_open_for_modules(X) ) M = new{typeof(X), AbsSpec, ModuleFP, Hecke.Map}(MD, OOX, Mpre) if check @@ -524,7 +561,7 @@ end Mpre = PreSheafOnScheme(X, production_func, restriction_func, OpenType=AbsSpec, OutputType=ModuleFP, RestrictionType=Hecke.Map, - is_open_func=_is_open_for_modules(X) + is_open_func=_is_open_func_for_schemes_without_specopen(X) ) M = new{typeof(X), AbsSpec, ModuleFP, Hecke.Map}(F, G, OOX, Mpre) @@ -705,7 +742,8 @@ end Blubber = PreSheafOnScheme(Y, production_func, restriction_func, OpenType=AbsSpec, OutputType=ModuleFP, RestrictionType=Hecke.Map, - is_open_func=_is_open_for_modules(Y) + is_open_func=_is_open_func_for_schemes_without_specopen(Y) + #is_open_func=_is_open_for_modules(Y) ) MY = new{typeof(Y), AbsSpec, ModuleFP, Hecke.Map}(inc, OOX, OOY, M, ident, Blubber) return MY diff --git a/test/Schemes/CoherentSheaves.jl b/test/Schemes/CoherentSheaves.jl index c84800a420a8..da6acc185921 100644 --- a/test/Schemes/CoherentSheaves.jl +++ b/test/Schemes/CoherentSheaves.jl @@ -26,7 +26,7 @@ simplify!(X) CC = coverings(X)[2] for U in patches(CC) - @test_broken !iszero(T(U)) + @test !iszero(T(U)) end HomM1M1 = oscar.HomSheaf(M1, M1) From c0b14db7cad46455414d3e3455b9555aa7ec653e Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Fri, 6 Jan 2023 13:44:13 +0100 Subject: [PATCH 06/14] Add the remaining methods for the restriction functions. --- experimental/Schemes/CoherentSheaves.jl | 181 +++++++++++++++++++++++- test/Schemes/CoherentSheaves.jl | 7 + 2 files changed, 181 insertions(+), 7 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 5bd6d3a307d6..8d65f6e3a6f4 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -255,7 +255,10 @@ identifications given by the glueings in the `default_covering`. OOX(V, U) ) end - function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::AbsSpec) + function restriction_func(F::AbsPreSheaf, + V::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, + U::AbsSpec + ) # We know that V can not be an ancestor of U, but U must be an affine chart. # Probably even an ancestor of V itself. W = __find_chart(V, default_covering(X)) @@ -346,16 +349,180 @@ identifications given by the glueings in the `default_covering`. return hom(F(V), F(U), img_gens, OOX(V, U)) end function restriction_func(F::AbsPreSheaf, V::PrincipalOpenSubset, U::SimplifiedSpec) - error("case not implemented") - end - function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::AbsSpec) - error("case not implemented") + if V === original(U) + return hom(F(V), F(U), gens(F(U)), OOX(V, U)) # If this had been more complicated, it would have been cached. + elseif some_ancestor(W->W===V, U) + W = original(U) + return compose(F(V, W), F(W, U)) + end + + # Below follow the more complicated cases. + success, _ = _have_common_ancestor(U, V) + if success + W = __find_chart(U, default_covering(X)) + gens_U = F(W, U).(gens(F(W))) # This will be caught by the preceeding clauses + gens_V = F(W, V).(gens(F(W))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(OOX(V, U)(c[i])*gens_U[i] + for i in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + end + + # Now we know we have a transition between different charts. + inc_U = _flatten_open_subscheme(U, default_covering(X)) + inc_V = _flatten_open_subscheme(V, default_covering(X)) + U_flat = codomain(inc_U) + V_flat = codomain(inc_V) + WU = ambient_scheme(U_flat) + WV = ambient_scheme(V_flat) + WU = __find_chart(U, default_covering(X)) + WV = __find_chart(V, default_covering(X)) + # The problem is: The generators of F(WU) may be different from + # those of F(U) and similarly for V. But the transition matrices + # are only described for those on WU and WV. Thus we need to + # implicitly do a base change. This is done by forwarding the generators + # of F(WU) to F(U) and expressing it in terms of the generators there. + gens_U = F(WU, U).(gens(F(WU))) # This will be caught by the preceeding clauses + gens_V = F(WV, V).(gens(F(WV))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + A = MG[(WV, WU)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[WU, WV]) + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(sum(OOX(V, U)(c[i])*OOX(WW, U)(A[i, j])*gens_U[j] + for i in 1:length(gens_V)) + for j in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) end function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::PrincipalOpenSubset) - error("case not implemented") + if V === ambient_scheme(U) + return hom(F(V), F(U), gens(F(U)), OOX(V, U)) # If this had been more complicated, it would have been cached. + elseif some_ancestor(W->W===V, U) + W = ambient_scheme(U) + return compose(F(V, W), F(W, U)) + end + + # Below follow the more complicated cases. + success, _ = _have_common_ancestor(U, V) + if success + W = __find_chart(U, default_covering(X)) + gens_U = F(W, U).(gens(F(W))) # This will be caught by the preceeding clauses + gens_V = F(W, V).(gens(F(W))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(OOX(V, U)(c[i])*gens_U[i] + for i in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + end + + # Now we know we have a transition between different charts. + inc_U = _flatten_open_subscheme(U, default_covering(X)) + inc_V = _flatten_open_subscheme(V, default_covering(X)) + U_flat = codomain(inc_U) + V_flat = codomain(inc_V) + WU = ambient_scheme(U_flat) + WV = ambient_scheme(V_flat) + WU = __find_chart(U, default_covering(X)) + WV = __find_chart(V, default_covering(X)) + # The problem is: The generators of F(WU) may be different from + # those of F(U) and similarly for V. But the transition matrices + # are only described for those on WU and WV. Thus we need to + # implicitly do a base change. This is done by forwarding the generators + # of F(WU) to F(U) and expressing it in terms of the generators there. + gens_U = F(WU, U).(gens(F(WU))) # This will be caught by the preceeding clauses + gens_V = F(WV, V).(gens(F(WV))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + A = MG[(WV, WU)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[WU, WV]) + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(sum(OOX(V, U)(c[i])*OOX(WW, U)(A[i, j])*gens_U[j] + for i in 1:length(gens_V)) + for j in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) end function restriction_func(F::AbsPreSheaf, V::SimplifiedSpec, U::SimplifiedSpec) - error("case not implemented") + V === U && return identity_map(F(U)) + + if V === original(U) + return hom(F(V), F(U), gens(F(U)), OOX(V, U)) # If this had been more complicated, it would have been cached. + elseif some_ancestor(W->W===V, U) + W = original(U) + return compose(F(V, W), F(W, U)) + end + + # Below follow the more complicated cases. + success, _ = _have_common_ancestor(U, V) + if success + W = __find_chart(U, default_covering(X)) + gens_U = F(W, U).(gens(F(W))) # This will be caught by the preceeding clauses + gens_V = F(W, V).(gens(F(W))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(OOX(V, U)(c[i])*gens_U[i] + for i in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) + end + + # Now we know we have a transition between different charts. + inc_U = _flatten_open_subscheme(U, default_covering(X)) + inc_V = _flatten_open_subscheme(V, default_covering(X)) + U_flat = codomain(inc_U) + V_flat = codomain(inc_V) + WU = ambient_scheme(U_flat) + WV = ambient_scheme(V_flat) + WU = __find_chart(U, default_covering(X)) + WV = __find_chart(V, default_covering(X)) + # The problem is: The generators of F(WU) may be different from + # those of F(U) and similarly for V. But the transition matrices + # are only described for those on WU and WV. Thus we need to + # implicitly do a base change. This is done by forwarding the generators + # of F(WU) to F(U) and expressing it in terms of the generators there. + gens_U = F(WU, U).(gens(F(WU))) # This will be caught by the preceeding clauses + gens_V = F(WV, V).(gens(F(WV))) + sub_V, inc = sub(F(V), gens_V) + img_gens = elem_type(F(U))[] + A = MG[(WV, WU)] # The transition matrix + WW, _ = glueing_domains(default_covering(X)[WU, WV]) + for v in gens(F(V)) + w = preimage(inc, v) # We know that inc is actually an isomorphism + c = coordinates(w) + w = sum(sum(OOX(V, U)(c[i])*OOX(WW, U)(A[i, j])*gens_U[j] + for i in 1:length(gens_V)) + for j in 1:length(gens_U) + ) + push!(img_gens, w) + end + return hom(F(V), F(U), img_gens, OOX(V, U)) end Mpre = PreSheafOnScheme(X, production_func, restriction_func, diff --git a/test/Schemes/CoherentSheaves.jl b/test/Schemes/CoherentSheaves.jl index da6acc185921..66c46e50700a 100644 --- a/test/Schemes/CoherentSheaves.jl +++ b/test/Schemes/CoherentSheaves.jl @@ -13,6 +13,11 @@ rr = L(U[1], W) rrr = L(U21, W) @test rr == compose(rho, rrr) + WW = simplify(W) + @test WW isa Oscar.SimplifiedSpec + rrWW = L(U[1], WW) + rrrWW = L(U21, WW) + @test rrWW == compose(rho, rrrWW) M1 = oscar.cotangent_sheaf(X) rho = M1(U[1], U21) @@ -28,6 +33,8 @@ for U in patches(CC) @test !iszero(T(U)) end + W = PrincipalOpenSubset(U[1], one(OO(U[1]))) + @test !iszero(T(W)) HomM1M1 = oscar.HomSheaf(M1, M1) rho = HomM1M1(U[1], U21) From 4ecf8235c591bacf05140d98c09f9c6f49d3ce86 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 09:28:12 +0100 Subject: [PATCH 07/14] Add inital values to summations. --- experimental/Schemes/CoherentSheaves.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 8d65f6e3a6f4..bd70800032d4 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -184,7 +184,7 @@ identifications given by the glueings in the `default_covering`. UU, _ = glueing_domains(default_covering(X)[U, V]) psi = OOX(UU, U) # Needs to exist by the checks of is_open_func, even though # in general UU ⊂ U! - return hom(MV, MU, [sum([psi(A[i, j]) * MU[j] for j in 1:ngens(MU)]) for i in 1:ngens(MV)], rho) + return hom(MV, MU, [sum([psi(A[i, j]) * MU[j] for j in 1:ngens(MU)]) for i in 1:ngens(MV), init=zero(MU)], rho) else error("invalid input") end @@ -217,7 +217,7 @@ identifications given by the glueings in the `default_covering`. # respect to the generators of F(W), so we have to map them manually down. # The call to F(W, U) will be handled by the above if-clauses. return hom(F(V), F(U), - [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))]) + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W)), init=zero(F(U))]) for i in 1:ngens(F(V))], OOX(V, U) ) @@ -250,7 +250,7 @@ identifications given by the glueings in the `default_covering`. # respect to the generators of F(W), so we have to map them manually down. # The call to F(W, U) will be handled by the above if-clauses. return hom(F(V), F(U), - [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))]) + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W)), init=zero(F(U))]) for i in 1:ngens(F(V))], OOX(V, U) ) @@ -717,7 +717,7 @@ end images = elem_type(MU)[] for phi in gens(MV) phi_map = element_to_homomorphism(phi) - images_f = [sum([B[i][j]*cod_res(phi_map(f[j])) for j in 1:length(f)]) for i in 1:length(B)] + images_f = [sum([B[i][j]*cod_res(phi_map(f[j])) for j in 1:length(f), init=zero(G(U))]) for i in 1:length(B)] psi = hom(F(U), G(U), images_f) push!(images, homomorphism_to_element(MU, psi)) end From 731e72ec67c45a6e24dfa611d9cb4291c2a56090 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 12:51:36 +0100 Subject: [PATCH 08/14] Add sample implementation for trivializations of coherent sheaves. --- experimental/Schemes/CoherentSheaves.jl | 169 +++++++++++++++++++++++- experimental/Schemes/Sheaves.jl | 5 +- 2 files changed, 171 insertions(+), 3 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index bd70800032d4..92031240fc57 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -966,7 +966,172 @@ function _pushforward(f::Hecke.Map{<:Ring, <:Ring}, I::Ideal, M::SubQuo) return MR, ident end -function is_locally_free(M::AbsCoherentSheaf) - return all(U->is_projective(M(U)), affine_charts(scheme(M))) +@attr Bool function is_locally_free(M::AbsCoherentSheaf) + return all(U->is_projective(M(U))[1], affine_charts(scheme(M))) end +#@attr Covering function trivializing_covering(M::AbsCoherentSheaf) +@attr function trivializing_covering(M::AbsCoherentSheaf) + X = scheme(M) + OOX = OO(X) + patch_list = Vector{AbsSpec}() + for U in affine_charts(X) + patch_list = vcat(patch_list, _trivializing_covering(M, U)) + end + C = Covering(patch_list) + fill_with_lazy_glueings!(C, X) + return C +end + +@attr function trivializing_covering(M::HomSheaf) + error("method not implemented") + # The problem is that every module of a HomSheaf must know that it is + # a hom-module. Hence, the way to go is to pass through a common + # refinement of domain and codomain and recreate all the hom modules + # as free modules on this covering. + # + # But for this, it is not yet clear where to locate the patches of these + # refinements in the tree and how to deal with the restriction maps in a + # clean way. Say M = Hom(F, G) where F is trivialized on {Uᵢ} and G on + # {Vⱼ}. Then W = Uᵢ∩ Vⱼ would have to be a PrincipalOpenSubset of both + # Uᵢ and Vⱼ for the restrictions of F and G to induce the proper job + # on restrictions to M(W) automatically. + # Hence, we need to manually prescribe how to trivialize and restrict + # M on the Ws. + dom_triv = trivializing_covering(domain(M)) + cod_triv = trivializing_covering(codomain(M)) + ref_list = _common_refinement_list(dom_triv, cod_triv) + C = Covering(ref_list) + fill_with_lazy_glueings!(C, scheme(M)) + return C +end + +function _trivializing_covering(M::AbsCoherentSheaf, U::AbsSpec) + X = scheme(M) + OOX = OO(X) + MU = M(U) + MU isa FreeMod && return [U] + MU::SubQuo + A = _presentation_matrix(MU) + if iszero(A) + # Trivial shortcut in the recursion. + # We nevertheless need to recreate U as a PrincipalOpenSubset of itself + # as we are not allowed to alter the values of the sheaf M on U directly. + V = PrincipalOpenSubset(U, one(OO(U))) + F = FreeMod(OO(V), ncols(A)) + res = hom(MU, F, gens(F), OOX(U, V)) + add_incoming_restriction(M, U, F, res) + object_cache(M)[V] = F + return [V] + end + + # We do not need to go through all entries of A, but only those + # necessary to generate the unit ideal. + I = ideal(OOX(U), [A[i, j] for i in 1:nrows(A) for j in 1:ncols(A)]) + one(OOX(U)) in I || error("sheaf is not locally trivial") + # The non-zero coordinates provide us with a list of entries which + # are sufficient to do so. This set can not assumed to be minimal, though. + a = coordinates(one(OOX(U)), I) + nonzero_entries = [ i for i in 1:ngens(I) if !iszero(a[i])] + return_patches = AbsSpec[] + + for t in nonzero_entries + i = div(t-1, ncols(A)) + 1 + j = mod(t-1, ncols(A)) + 1 # The matrix coordinates of the nonzero entry + # We invert the (i,j)-th entry of A. + # Then we can reduce the presentation matrix so that we can throw away one + # of the generators of the module. + V = PrincipalOpenSubset(U, A[i, j]) + Ares = map_entries(OOX(U, V), A) + uinv = inv(Ares[i, j]) + multiply_row!(Ares, uinv, i) + for k in 1:i-1 + #multiply_row!(Ares, u, k) + add_row!(Ares, -A[k, j], i, k) + end + for k in i+1:nrows(Ares) + #multiply_row!(Ares, u, k) + add_row!(Ares, -A[k, j], i, k) + end + Asub = Ares[[k for k in 1:nrows(Ares) if k != i], [k for k in 1:ncols(Ares) if k !=j]] + + # Assemble the restriction map from the parent node + if iszero(Asub) + # End of recursion. + # Create a free module and the corresponding restriction morphism. + F = FreeMod(OO(V), ncols(Asub)) + img_gens = elem_type(F)[] + for k in 1:j-1 + push!(img_gens, F[k]) + end + push!(img_gens, + -sum([Ares[i, k]*F[(k>j ? k-1 : k)] for k in 1:ncols(Ares) if k!=j], + init=zero(F)) + ) + for k in j+1:ncols(Ares) + push!(img_gens, F[k-1]) + end + res = hom(MU, F, img_gens, OOX(U, V)) + + # Since we are messing with the internals of the sheaf, we need + # to leave everything clean. This includes manual caching. + add_incoming_restriction!(M, U, F, res) + object_cache(M)[V] = F + set_attribute!(F, :_presentation_matrix, Asub) + push!(return_patches, V) + else + # Intermediate recursion step. + # Recreate the restriction of the module to the open subset but with one generator + # less and construct the restriction map. + F, amb_res = change_base_ring(OOX(U, V), ambient_free_module(MU)) + v = ambient_representatives_generators(MU) + M_gens = amb_res.(v) + rest_gens = [M_gens[k] for k in 1:length(M_gens) if k!=j] + rels = [amb_res(w) for w in relations(MU)] + MV = SubQuo(F, rest_gens, rels) + img_gens = elem_type(F)[] + for k in 1:j-1 + push!(img_gens, M_gens[k]) + end + push!(img_gens, + -sum([Ares[i, k]*M_gens[k] for k in 1:length(M_gens) if k!=j], + init=zero(F)) + ) + for k in j+1:length(M_gens) + push!(img_gens, M_gens[k]) + end + res = hom(MU, MV, MV.(img_gens), OOX(U, V)) + add_incoming_restriction!(M, U, MV, res) + object_cache(M)[V] = MV + set_attribute!(MV, :_presentation_matrix, Asub) + return_patches = vcat(return_patches, _trivializing_covering(M, V)) + end + end + return return_patches +end + +@attr MatrixElem function _presentation_matrix(M::ModuleFP) + return matrix(map(presentation(M), 1)) +end + +function fill_with_lazy_glueings!(C::Covering, X::AbsCoveredScheme) + # TODO: Fill in all the implicit and restricted glueings from X. + # We assume that all patches in C are in a tree structure eventually + # leading to affine charts of X. + return C +end + +function _common_refinement_list(C::Covering, D::Covering) + patch_list = AbsSpec[] + for U in patches(C) + for V in patches(D) + success, W = _have_common_ancestor(U, V) + if success + #TODO: Model the intersection of both U and V with an appropriate + #place in the tree structure. + error("method not implemented") + end + end + end + return patch_list +end diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index 7dd9c61ef844..4c519a09f915 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -60,6 +60,10 @@ function is_open_func(F::AbsPreSheaf) return is_open_func(underlying_presheaf(F)) end +function object_cache(F::AbsPreSheaf) + return object_cache(underlying_presheaf(F)) +end + ######################################################################## # Implementation of PreSheafOnScheme # ######################################################################## @@ -113,7 +117,6 @@ end @Markdown.doc """ add_incoming_restriction!(F::AbsPreSheaf{<:Any, OpenType, <:Any, RestrictionType}, U::OpenType, - V::OpenType, rho::RestrictionType ) where {OpenType, RestrictionType} From 454fca9a98492872cafffe02af0ef79a893e6c8a Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 12:52:21 +0100 Subject: [PATCH 09/14] Add tests. --- test/Schemes/VectorBundles.jl | 34 ++++++++++++++++++++++++++++++++++ test/Schemes/runtests.jl | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/Schemes/VectorBundles.jl diff --git a/test/Schemes/VectorBundles.jl b/test/Schemes/VectorBundles.jl new file mode 100644 index 000000000000..7c2753521c7b --- /dev/null +++ b/test/Schemes/VectorBundles.jl @@ -0,0 +1,34 @@ +@testset "trivializations of coherent sheaves" begin + IP2 = projective_space(QQ, 2) + S = ambient_coordinate_ring(IP2) + (x,y,z) = gens(S) + f = x^2 + y*z + IPC = subscheme(IP2, f) + C = covered_scheme(IPC) + set_name!(C, "C") + WC = cotangent_sheaf(C) + @test is_locally_free(WC) + V = oscar.trivializing_covering(WC) + U = affine_charts(C) + @test WC(U[1], V[1]) isa ModuleFPHom + W = PrincipalOpenSubset(V[2], first(gens(OO(V[2])))) + res = WC(V[1], W) + v = res(first(gens(WC(V[1])))) + @test coordinates(v)[1] == -inv(first(gens(OO(W))))^2 + + TC = tangent_sheaf(C) + @test_broken oscar.trivializing_covering(TC) isa Covering + + IP4 = projective_space(QQ, 4) + S = ambient_coordinate_ring(IP4) + (x,y,z,u,v) = gens(S) + A = S[x y z; u v x] + I = ideal(S, minors(A, 2)) + IPX = subscheme(IP4, I) + X = covered_scheme(IPX) + set_name!(X, "X") + WX = cotangent_sheaf(X) + C = oscar.trivializing_covering(WX) + @test WX(C[1]) isa FreeMod + @test !any(x->x===ambient_scheme(C[1]), affine_charts(X)) # codimension 2 means recursion depth >= 2. +end diff --git a/test/Schemes/runtests.jl b/test/Schemes/runtests.jl index de3b7295972d..bec6c290afb5 100644 --- a/test/Schemes/runtests.jl +++ b/test/Schemes/runtests.jl @@ -15,4 +15,4 @@ include("WeilDivisor.jl") include("CoveredProjectiveSchemes.jl") include("CoherentSheaves.jl") include("SimplifiedSpec.jl") - +include("VectorBundles.jl") From a4974157784f860da38e2a6aaec84b46db09905e Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 13:52:52 +0100 Subject: [PATCH 10/14] Implement trivializations of HomSheaf. --- experimental/Schemes/CoherentSheaves.jl | 82 ++++++++++++++++++++----- experimental/Schemes/Sheaves.jl | 22 ++++++- experimental/Schemes/SimplifiedSpec.jl | 78 +++++++++++++++++++++++ experimental/Schemes/Types.jl | 14 +++-- test/Schemes/VectorBundles.jl | 5 +- 5 files changed, 174 insertions(+), 27 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 92031240fc57..23b6f764674d 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -82,18 +82,39 @@ function _is_open_for_modules(X::AbsCoveredScheme) return X === Y === Z end function is_open_func(U::AbsSpec, V::AbsSpec) - U in affine_charts(X) || return false - V in affine_charts(X) || return false - G = affine_charts(X)[U, V] + any(x->x===U, affine_charts(X)) || return false + any(x->x===V, affine_charts(X)) || return false + G = default_covering(X)[U, V] return issubset(U, glueing_domains(G)[1]) end - function is_open_func(U::PrincipalOpenSubset, V::AbsSpec) - V in affine_charts(X) || return false - ambient_scheme(U) === V && return true - W = ambient_scheme(U) - W in affine_charts(X) || return false + function is_open_func( + U::AbsSpec, + V::Union{<:PrincipalOpenSubset, <:SimplifiedSpec} + ) + issubset(U, V) && return true + any(x->x===U, affine_charts(X)) || return false + inc_V_flat = _flatten_open_subscheme(V, default_covering(X)) + A = ambient_scheme(codomain(inc_V_flat)) + Vdirect = codomain(inc_V_flat) + W = ambient_scheme(Vdirect) + haskey(glueings(default_covering(X)), (W, U)) || return false # In this case, they are not glued + G = default_covering(X)[W, U] + f, g = glueing_morphisms(G) + pre_V = preimage(g, V) + return is_subset(U, pre_V) + end + function is_open_func( + U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, + V::AbsSpec + ) + any(x->x===V, affine_charts(X)) || return false + inc_U_flat = _flatten_open_subscheme(U, default_covering(X)) + A = ambient_scheme(codomain(inc_U_flat)) + Udirect = codomain(inc_U_flat) + W = ambient_scheme(Udirect) + haskey(glueings(default_covering(X)), (W, V)) || return false # In this case, they are not glued G = default_covering(X)[W, V] - return is_subset(U, glueing_domains(G)[1]) + return is_subset(Udirect, glueing_domains(G)[1]) end return is_open_func end @@ -184,7 +205,7 @@ identifications given by the glueings in the `default_covering`. UU, _ = glueing_domains(default_covering(X)[U, V]) psi = OOX(UU, U) # Needs to exist by the checks of is_open_func, even though # in general UU ⊂ U! - return hom(MV, MU, [sum([psi(A[i, j]) * MU[j] for j in 1:ngens(MU)]) for i in 1:ngens(MV), init=zero(MU)], rho) + return hom(MV, MU, [sum([psi(A[i, j]) * MU[j] for j in 1:ngens(MU)], init=zero(MU)) for i in 1:ngens(MV)], OOX(V, U)) else error("invalid input") end @@ -217,7 +238,7 @@ identifications given by the glueings in the `default_covering`. # respect to the generators of F(W), so we have to map them manually down. # The call to F(W, U) will be handled by the above if-clauses. return hom(F(V), F(U), - [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W)), init=zero(F(U))]) + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))], init=zero(F(U))) for i in 1:ngens(F(V))], OOX(V, U) ) @@ -250,7 +271,7 @@ identifications given by the glueings in the `default_covering`. # respect to the generators of F(W), so we have to map them manually down. # The call to F(W, U) will be handled by the above if-clauses. return hom(F(V), F(U), - [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W)), init=zero(F(U))]) + [sum([OOX(WW, U)(A[i, j])*F(W, U)(F(W)[j]) for j in 1:ngens(F(W))], init=zero(F(U))) for i in 1:ngens(F(V))], OOX(V, U) ) @@ -717,7 +738,7 @@ end images = elem_type(MU)[] for phi in gens(MV) phi_map = element_to_homomorphism(phi) - images_f = [sum([B[i][j]*cod_res(phi_map(f[j])) for j in 1:length(f), init=zero(G(U))]) for i in 1:length(B)] + images_f = [sum([B[i][j]*cod_res(phi_map(f[j])) for j in 1:length(f)], init=zero(G(U))) for i in 1:length(B)] psi = hom(F(U), G(U), images_f) push!(images, homomorphism_to_element(MU, psi)) end @@ -984,7 +1005,8 @@ end end @attr function trivializing_covering(M::HomSheaf) - error("method not implemented") + X = scheme(M) + OOX = OO(X) # The problem is that every module of a HomSheaf must know that it is # a hom-module. Hence, the way to go is to pass through a common # refinement of domain and codomain and recreate all the hom modules @@ -1000,8 +1022,31 @@ end # M on the Ws. dom_triv = trivializing_covering(domain(M)) cod_triv = trivializing_covering(codomain(M)) - ref_list = _common_refinement_list(dom_triv, cod_triv) - C = Covering(ref_list) + patch_list = AbsSpec[] + for U in patches(dom_triv) + for V in patches(cod_triv) + success, W = _have_common_ancestor(U, V) + if success + incU = _flatten_open_subscheme(U, W) + incV = _flatten_open_subscheme(V, W) + UV = intersect(codomain(incU), codomain(incV))::PrincipalOpenSubset + push!(patch_list, UV) + + dom_UV, dom_res = change_base_ring(OOX(U, UV), domain(M)(U)) + add_incoming_restriction!(domain(M), U, dom_UV, dom_res) + add_incoming_restriction!(domain(M), W, dom_UV, + compose(domain(M)(W, U), dom_res)) + object_cache(domain(M))[UV] = dom_UV + + cod_UV, cod_res = change_base_ring(OOX(V, UV), codomain(M)(V)) + add_incoming_restriction!(codomain(M), V, cod_UV, cod_res) + add_incoming_restriction!(codomain(M), W, dom_UV, + compose(codomain(M)(W, V), cod_res)) + object_cache(codomain(M))[UV] = cod_UV + end + end + end + C = Covering(patch_list) fill_with_lazy_glueings!(C, scheme(M)) return C end @@ -1129,7 +1174,10 @@ function _common_refinement_list(C::Covering, D::Covering) if success #TODO: Model the intersection of both U and V with an appropriate #place in the tree structure. - error("method not implemented") + incU = _flatten_open_subscheme(U, W) + incV = _flatten_open_subscheme(V, W) + UV = intersect(codomain(incU), codomain(incV)) + push!(patch_list, UV) end end end diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index 4c519a09f915..a11ddb2d6950 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -217,16 +217,32 @@ function _is_open_func_for_schemes(X::AbsCoveredScheme) return X === Y === Z end function is_open_func(U::AbsSpec, V::AbsSpec) - U in affine_charts(X) || return false - V in affine_charts(X) || return false + any(x->x===U, affine_charts(X)) || return false + any(x->x===U, affine_charts(X)) || return false G = default_covering(X)[U, V] return issubset(U, glueing_domains(G)[1]) end + function is_open_func( + U::AbsSpec, + V::Union{<:PrincipalOpenSubset, <:SimplifiedSpec} + ) + issubset(U, V) && return true + any(x->x===U, affine_charts(X)) || return false + inc_V_flat = _flatten_open_subscheme(V, default_covering(X)) + A = ambient_scheme(codomain(inc_V_flat)) + Vdirect = codomain(inc_V_flat) + W = ambient_scheme(Vdirect) + haskey(glueings(default_covering(X)), (W, U)) || return false # In this case, they are not glued + G = default_covering(X)[W, U] + f, g = glueing_morphisms(G) + pre_V = preimage(g, V) + return is_subset(U, pre_V) + end function is_open_func( U::Union{<:PrincipalOpenSubset, <:SimplifiedSpec}, V::AbsSpec ) - V in affine_charts(X) || return false + any(x->x===V, affine_charts(X)) || return false inc_U_flat = _flatten_open_subscheme(U, default_covering(X)) A = ambient_scheme(codomain(inc_U_flat)) Udirect = codomain(inc_U_flat) diff --git a/experimental/Schemes/SimplifiedSpec.jl b/experimental/Schemes/SimplifiedSpec.jl index 59dcbfb99e02..919257398f28 100644 --- a/experimental/Schemes/SimplifiedSpec.jl +++ b/experimental/Schemes/SimplifiedSpec.jl @@ -171,6 +171,84 @@ function _flatten_open_subscheme( return _flatten_open_subscheme(W, C, iso=new_iso) end +function _flatten_open_subscheme( + U::PrincipalOpenSubset, P::AbsSpec; + iso::AbsSpecMor=begin + UU = PrincipalOpenSubset(U, one(OO(U))) + f = SpecMor(U, UU, hom(OO(UU), OO(U), gens(OO(U)), check=false), check=false) + f_inv = SpecMor(UU, U, hom(OO(U), OO(UU), gens(OO(UU)), check=false), check=false) + set_attribute!(f, :inverse, f_inv) + set_attribute!(f_inv, :inverse, f) + f + end + ) + some_ancestor(W->W===P, U) || error("ancestor not found") + W = ambient_scheme(U) + V = domain(iso) + UV = codomain(iso) + hV = complement_equation(UV) + hU = complement_equation(U) + WV = PrincipalOpenSubset(W, OO(W).([lifted_numerator(hU), lifted_numerator(hV)])) + ident = SpecMor(UV, WV, hom(OO(WV), OO(UV), gens(OO(UV)), check=false), check=false) + new_iso = compose(iso, ident) + new_iso_inv = compose(inverse(ident), inverse(iso)) + set_attribute!(new_iso, :inverse, new_iso_inv) + set_attribute!(new_iso_inv, :inverse, new_iso) + if W === P + return new_iso + end + return _flatten_open_subscheme(W, P, iso=new_iso) +end + +function _flatten_open_subscheme( + U::SimplifiedSpec, P::AbsSpec; + iso::AbsSpecMor=begin + UU = PrincipalOpenSubset(U, one(OO(U))) + f = SpecMor(U, UU, hom(OO(UU), OO(U), gens(OO(U)), check=false), check=false) + f_inv = SpecMor(UU, U, hom(OO(U), OO(UU), gens(OO(UU)), check=false), check=false) + set_attribute!(f, :inverse, f_inv) + set_attribute!(f_inv, :inverse, f) + f + end + ) + some_ancestor(W->W===P, U) || error("ancestor not found") + W = original(U) + V = domain(iso) + UV = codomain(iso)::PrincipalOpenSubset + hV = complement_equation(UV) + f, g = identification_maps(U) + hVW = pullback(g)(hV) + WV = PrincipalOpenSubset(W, hVW) + ident = SpecMor(UV, WV, + hom(OO(WV), OO(UV), + OO(UV).(pullback(f).(gens(ambient_coordinate_ring(WV)))), + check=false), + check=false) + new_iso = compose(iso, ident) + new_iso_inv = compose(inverse(ident), inverse(iso)) + set_attribute!(new_iso, :inverse, new_iso_inv) + set_attribute!(new_iso_inv, :inverse, new_iso) + if W === P + return new_iso + end + return _flatten_open_subscheme(W, P, iso=new_iso) +end + +function _flatten_open_subscheme( + U::AbsSpec, P::AbsSpec; + iso::AbsSpecMor=begin + UU = PrincipalOpenSubset(U, one(OO(U))) + f = SpecMor(U, UU, hom(OO(UU), OO(U), gens(OO(U)), check=false), check=false) + f_inv = SpecMor(UU, U, hom(OO(U), OO(UU), gens(OO(UU)), check=false), check=false) + set_attribute!(f, :inverse, f_inv) + set_attribute!(f_inv, :inverse, f) + f + end + ) + U === P || error("schemes have no valid relationship") + return iso +end + ######################################################################## # Lookup of common ancestors # # # diff --git a/experimental/Schemes/Types.jl b/experimental/Schemes/Types.jl index 61fd9cd7646d..4b5f09261e6b 100644 --- a/experimental/Schemes/Types.jl +++ b/experimental/Schemes/Types.jl @@ -420,11 +420,14 @@ identifications given by the glueings in the `default_covering`. ) OV = F(V) OU = F(U) - incV, dV = _find_chart(V, default_covering(X)) - W = codomain(incV) - V_direct = PrincipalOpenSubset(W, dV) + incV = _flatten_open_subscheme(V, default_covering(X)) + W = ambient_scheme(codomain(incV)) + V_direct = domain(incV) if W === U - return pullback(inverse(incV)) + # By virtue of the checks in _is_open_func we must have V isomorphic to U. + phi = pullback(inverse(incV)) + psi = hom(OO(V_direct), OU, gens(OU)) + return hom(OV, OU, psi.(phi.(gens(OV)))) ### deprecated code below; # kept for the moment because of possible incompatibilities with glueings # along SpecOpens. @@ -440,8 +443,7 @@ identifications given by the glueings in the `default_covering`. W1, W2 = glueing_domains(G) f, g = glueing_morphisms(G) g_res = restrict(g, U, V_direct) - inc_res = restrict(incV, V, V_direct, check=false) - return pullback(compose(g_res, inverse(inc_res))) + return pullback(compose(g_res, inverse(incV))) ### deprecated code below; see comment above function rho_func2(a::RingElem) parent(a) === OV || error("element does not belong to the correct ring") diff --git a/test/Schemes/VectorBundles.jl b/test/Schemes/VectorBundles.jl index 7c2753521c7b..36324c7cd8a3 100644 --- a/test/Schemes/VectorBundles.jl +++ b/test/Schemes/VectorBundles.jl @@ -17,7 +17,7 @@ @test coordinates(v)[1] == -inv(first(gens(OO(W))))^2 TC = tangent_sheaf(C) - @test_broken oscar.trivializing_covering(TC) isa Covering + @test oscar.trivializing_covering(TC) isa Covering IP4 = projective_space(QQ, 4) S = ambient_coordinate_ring(IP4) @@ -31,4 +31,7 @@ C = oscar.trivializing_covering(WX) @test WX(C[1]) isa FreeMod @test !any(x->x===ambient_scheme(C[1]), affine_charts(X)) # codimension 2 means recursion depth >= 2. + TX = tangent_sheaf(X) + CC = oscar.trivializing_covering(TX) + @test all(x->TX(x) isa FreeMod, patches(CC)) end From 5891c17603e158b4faf06af426422c6b2d90877d Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 20:00:46 +0100 Subject: [PATCH 11/14] Add tests and fixes. --- experimental/Schemes/CoherentSheaves.jl | 40 +++++++++++++++++++++++-- experimental/Schemes/Sheaves.jl | 7 +++++ test/Schemes/VectorBundles.jl | 27 +++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 23b6f764674d..29db718a8e43 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -220,8 +220,7 @@ identifications given by the glueings in the `default_covering`. # If the restriction was more complicated than what follows, then # it would have been cached earlier and this call would not have happened # This is the end of the recursion induced in the next elseif below. - W = ambient_scheme(U) - res = hom(F(W), F(U), gens(MU), OOX(W, U)) + res = hom(F(V), F(U), gens(F(U)), OOX(W, U)) return res elseif some_ancestor(W->(W === V), U) W = ambient_scheme(U) @@ -1040,9 +1039,44 @@ end cod_UV, cod_res = change_base_ring(OOX(V, UV), codomain(M)(V)) add_incoming_restriction!(codomain(M), V, cod_UV, cod_res) - add_incoming_restriction!(codomain(M), W, dom_UV, + add_incoming_restriction!(codomain(M), W, cod_UV, compose(codomain(M)(W, V), cod_res)) object_cache(codomain(M))[UV] = cod_UV + + MUV = M(UV) # This will be a free module; we need to prescribe the restrictions! + MW = M(W) + img_gens = elem_type(MUV)[] + # every generator g of MW is a homomorphism. It takes an element + # v ∈ domain(M)(W) to w = ϕ_{g}(v) ∈ codomain(M)(W). + # Where does g map to when restricting to MUV? + # + for g in gens(MW) + phi = element_to_homomorphism(g) + img_gens_phi = cod_res.(codomain(M)(W, V).(phi.(gens(domain(M)(W))))) + sub_dom, inc_dom = sub(domain(M)(UV), + domain(M)(W, UV).(gens(domain(M)(W)))) + #dom_res.(domain(M)(W, U).(gens(domain(M)(W))))) + img_gens_psi = elem_type(codomain(M)(UV))[] + for v in gens(domain(M)(UV)) + w = preimage(inc_dom, v) + c = coordinates(w) # These are the coordinates in the original set + # of generators in the domain + # We use this to compute the image of v + phi_v = sum([c[i]*img_gens_phi[i] for i in 1:length(img_gens_phi)], init=zero(codomain(M)(UV))) + # and push it to the list. + push!(img_gens_psi, phi_v) + end + # From that list, we can assemble what the restriction of phi + # looks like as a homomorphism + psi = hom(domain(M)(UV), codomain(M)(UV), img_gens_psi) + # and convert it to a module element. + img_g = homomorphism_to_element(MUV, psi) + push!(img_gens, img_g) + end + + # Finally, this allows us to assemble the restriction map + res = hom(MW, MUV, img_gens, OOX(W, UV)) + add_incoming_restriction!(M, W, MUV, res) end end end diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index a11ddb2d6950..b8497e4b8db0 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -109,6 +109,10 @@ function restriction_map(F::PreSheafOnScheme{<:Any, OpenType, OutputType, Restri # Hand the production of the restriction over to the internal method rho = restriction_func(F)(F, U, V) + # Sanity checks + domain(rho) === F(U) || error("domain of the produced restrition is not correct") + codomain(rho) === F(V) || error("codomain of the produced restrition is not correct") + # Cache the result in the attributes of F(V) inc isa IdDict{<:OpenType, <:RestrictionType} && (inc[U] = rho) # It is the restriction coming from U. return rho::RestrictionType @@ -136,6 +140,9 @@ function add_incoming_restriction!(F::AbsPreSheaf{<:Any, OpenType, OutputType, R incoming_res = incoming_restrictions(F, M) incoming_res == nothing && return F # This indicates that no incoming_res::IdDict{<:OpenType, <:RestrictionType} + # sanity checks + domain(rho) === F(U) || error("domain is not correct") + codomain(rho) === M || error("codomain is not correct") incoming_res[U] = rho return F end diff --git a/test/Schemes/VectorBundles.jl b/test/Schemes/VectorBundles.jl index 36324c7cd8a3..f23ab1cbd229 100644 --- a/test/Schemes/VectorBundles.jl +++ b/test/Schemes/VectorBundles.jl @@ -33,5 +33,32 @@ @test !any(x->x===ambient_scheme(C[1]), affine_charts(X)) # codimension 2 means recursion depth >= 2. TX = tangent_sheaf(X) CC = oscar.trivializing_covering(TX) + + # Testing transitions across charts while going down in the trees. @test all(x->TX(x) isa FreeMod, patches(CC)) + A = PrincipalOpenSubset(CC[1], gens(OO(CC[1]))[1]) + UU = simplify(A) + @test TX(CC[1], UU) isa ModuleFPHom + UUU = PrincipalOpenSubset(UU, one(OO(UU))) + @test TX(CC[1], UUU) isa ModuleFPHom + B = PrincipalOpenSubset(CC[2], one(OO(CC[2]))) + @test oscar.is_open_func(TX)(A, B) + @test WX(B, A) isa ModuleFPHom + @test TX(B, A) isa ModuleFPHom + @test TX(B, UU) == compose(TX(B, A), TX(A, UU)) + @test TX(B, UUU) == compose(TX(B, A), TX(A, UUU)) + @test TX(B, UUU) == compose(TX(B, UU), TX(UU, UUU)) + BU = simplify(B) + BUU = PrincipalOpenSubset(BU, one(OO(BU))) + @test WX(BU, A) isa ModuleFPHom + @test TX(BU, A) isa ModuleFPHom + @test TX(BU, UU) == compose(TX(BU, A), TX(A, UU)) + @test TX(BU, UUU) == compose(TX(BU, A), TX(A, UUU)) + @test TX(BU, UUU) == compose(TX(BU, UU), TX(UU, UUU)) + @test WX(BUU, A) isa ModuleFPHom + @test TX(BUU, A) isa ModuleFPHom + @test TX(BUU, UU) == compose(TX(BUU, A), TX(A, UU)) + @test TX(BUU, UUU) == compose(TX(BUU, A), TX(A, UUU)) + @test TX(BUU, UUU) == compose(TX(BUU, UU), TX(UU, UUU)) + @test !iszero(TX(BUU, UUU)) end From f0912d70f6ff9a2435bf0ec1d0863c4d617677d6 Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 20:02:22 +0100 Subject: [PATCH 12/14] Remove superfluous method. --- experimental/Schemes/CoherentSheaves.jl | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/experimental/Schemes/CoherentSheaves.jl b/experimental/Schemes/CoherentSheaves.jl index 29db718a8e43..f24cd1a61af0 100644 --- a/experimental/Schemes/CoherentSheaves.jl +++ b/experimental/Schemes/CoherentSheaves.jl @@ -1200,20 +1200,3 @@ function fill_with_lazy_glueings!(C::Covering, X::AbsCoveredScheme) return C end -function _common_refinement_list(C::Covering, D::Covering) - patch_list = AbsSpec[] - for U in patches(C) - for V in patches(D) - success, W = _have_common_ancestor(U, V) - if success - #TODO: Model the intersection of both U and V with an appropriate - #place in the tree structure. - incU = _flatten_open_subscheme(U, W) - incV = _flatten_open_subscheme(V, W) - UV = intersect(codomain(incU), codomain(incV)) - push!(patch_list, UV) - end - end - end - return patch_list -end From 3dfdc3795ef48bda65a0bc805691e7fa95a6c6ac Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 21:50:56 +0100 Subject: [PATCH 13/14] Add special constructor for PrincipalOpenSubsets. --- experimental/Schemes/Sheaves.jl | 7 ++++--- src/Schemes/PrincipalOpenSubset/Objects/Types.jl | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index b8497e4b8db0..541031198263 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -82,7 +82,7 @@ function (F::PreSheafOnScheme{<:Any, OpenType, OutputType})(U::T; cached::Bool=t haskey(object_cache(F), U) && return (object_cache(F)[U])::OutputType # Testing openness might be expensive, so it can be skipped - check && is_open_func(F)(U, space(F)) || error("the given set is not open or admissible") + check && (is_open_func(F)(U, space(F)) || error("the given set is not open or admissible")) G = production_func(F)(F, U) cached && (object_cache(F)[U] = G) return G::OutputType @@ -97,14 +97,15 @@ end For a `F` produce (and cache) the restriction map `F(U) → F(V)`. """ function restriction_map(F::PreSheafOnScheme{<:Any, OpenType, OutputType, RestrictionType}, - U::Type1, V::Type2 + U::Type1, V::Type2; + check::Bool=true ) where {OpenType, OutputType, RestrictionType, Type1<:OpenType, Type2<:OpenType} # First, look up whether this restriction had already been asked for previously. inc = incoming_restrictions(F, F(V)) !(inc == nothing) && haskey(inc, U) && return (inc[U])::RestrictionType # Check whether the given pair is even admissible. - is_open_func(F)(V, U) || error("the second argument is not open in the first") + check && (is_open_func(F)(V, U) || error("the second argument is not open in the first")) # Hand the production of the restriction over to the internal method rho = restriction_func(F)(F, U, V) diff --git a/src/Schemes/PrincipalOpenSubset/Objects/Types.jl b/src/Schemes/PrincipalOpenSubset/Objects/Types.jl index bae55fa104b1..d1bff46b4ab6 100644 --- a/src/Schemes/PrincipalOpenSubset/Objects/Types.jl +++ b/src/Schemes/PrincipalOpenSubset/Objects/Types.jl @@ -20,5 +20,21 @@ export PrincipalOpenSubset U = hypersurface_complement(X, f) return new{base_ring_type(X), ring_type(U), typeof(X)}(X, U, (length(f)>0 ? prod(f) : one(OO(X)))) end + + # The following constructors allow to pass a ring as an extra argument. + # It is assumed that the complement of f in X is isomorphic to Spec(R). + function PrincipalOpenSubset(X::AbsSpec, R::Ring, f::RingElem; + check::Bool=true + ) + U = Spec(R) + check && (U == hypersurface_complement(X, f) || error("scheme is not isomorphic to the anticipated open subset")) + return new{base_ring_type(X), ring_type(U), typeof(X)}(X, U, f) + end + function PrincipalOpenSubset(X::AbsSpec, R::Ring, f::Vector{T}; + check::Bool=true + ) where {T<:RingElem} + d = prod(length(f) > 0 ? f : one(OO(X))) + return PrincipalOpenSubset(X, R, d) + end end From 12fbf05c7f0fba1d11c4d3232555e3a385146dac Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Mon, 9 Jan 2023 22:59:53 +0100 Subject: [PATCH 14/14] Disable internal some checks for the moment. --- experimental/Schemes/Sheaves.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/experimental/Schemes/Sheaves.jl b/experimental/Schemes/Sheaves.jl index 541031198263..c42a3d5bf411 100644 --- a/experimental/Schemes/Sheaves.jl +++ b/experimental/Schemes/Sheaves.jl @@ -111,8 +111,9 @@ function restriction_map(F::PreSheafOnScheme{<:Any, OpenType, OutputType, Restri rho = restriction_func(F)(F, U, V) # Sanity checks - domain(rho) === F(U) || error("domain of the produced restrition is not correct") - codomain(rho) === F(V) || error("codomain of the produced restrition is not correct") + # disabled for the moment because of the ideal sheaves: They use the ring maps. + #domain(rho) === F(U) || error("domain of the produced restrition is not correct") + #codomain(rho) === F(V) || error("codomain of the produced restrition is not correct") # Cache the result in the attributes of F(V) inc isa IdDict{<:OpenType, <:RestrictionType} && (inc[U] = rho) # It is the restriction coming from U.