Skip to content

Commit

Permalink
De Rham complexes (oscar-system#2895)
Browse files Browse the repository at this point in the history
* Implement de Rham complexes for the four basic ring types.
  • Loading branch information
HechtiDerLachs authored Oct 28, 2023
1 parent 81e41e1 commit 62a8627
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Modules/ExteriorPowers/SubQuo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function exterior_power(M::SubquoModule, p::Int; cached::Bool=true)
else
C = presentation(M)
phi = map(C, 1)
codomain(phi).S = Symbol.(["$e" for e in gens(M)])
result, mm = _exterior_power(phi, p)
end

Expand Down
1 change: 1 addition & 0 deletions src/Modules/Modules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ include("local_rings.jl")
include("mpolyquo.jl")
include("flattenings.jl")
include("ExteriorPowers/ExteriorPowers.jl")
include("deRhamComplexes.jl")

#include("Iterators.jl") # inclusion postponed to src/InvariantTheory/InvariantTheory.jl due to dependencies
208 changes: 208 additions & 0 deletions src/Modules/deRhamComplexes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# By default we cache the Kaehler differentials and their
# exterior powers in the attributes of the ring. This
# internal function maintains that structure.
function _kaehler_differentials(R::Ring)
if !has_attribute(R, :kaehler_differentials)
set_attribute!(R, :kaehler_differentials, Dict{Int, ModuleFP}())
end
return get_attribute(R, :kaehler_differentials)::Dict{Int, <:ModuleFP}
end

function kaehler_differentials(R::Union{MPolyRing, MPolyLocRing}; cached::Bool=true)
if cached && haskey(_kaehler_differentials(R), 1)
return _kaehler_differentials(R)[1]
end
n = ngens(R)
result = FreeMod(R, n)
symb = symbols(R)
result.S = [Symbol("d"*String(symb[i])) for i in 1:n]
set_attribute!(result, :show, show_kaehler_differentials)

cached && (_kaehler_differentials(R)[1] = result)
set_attribute!(result, :is_kaehler_differential_module, (R, 1))
return result
end

function kaehler_differentials(R::MPolyQuoRing; cached::Bool=true)
if cached && haskey(_kaehler_differentials(R), 1)
return _kaehler_differentials(R)[1]
end
n = ngens(R)
P = base_ring(R)
OmegaP = kaehler_differentials(P)
f = gens(modulus(R))
r = length(f)
Pr = FreeMod(P, r)
phi = hom(Pr, OmegaP, [exterior_derivative(a, parent=OmegaP) for a in f])
phi_res, _, _ = change_base_ring(R, phi)
M = cokernel(phi_res)
set_attribute!(M, :show, show_kaehler_differentials)

cached && (_kaehler_differentials(R)[1] = M)
set_attribute!(M, :is_kaehler_differential_module, (R, 1))
return M
end

function kaehler_differentials(R::MPolyQuoLocRing; cached::Bool=true)
if cached && haskey(_kaehler_differentials(R), 1)
return _kaehler_differentials(R)[1]
end
n = ngens(R)
P = localized_ring(R)
OmegaP = kaehler_differentials(P)
f = gens(modulus(R))
r = length(f)
Pr = FreeMod(P, r)
phi = hom(Pr, OmegaP, [exterior_derivative(a, parent=OmegaP) for a in f])
phi_res, _, _ = change_base_ring(R, phi)
M = cokernel(phi_res)[1]
set_attribute!(M, :show, show_kaehler_differentials)

cached && (_kaehler_differentials(R)[1] = M)
set_attribute!(M, :is_kaehler_differential_module, (R, 1))
return M
end

@doc raw"""
kaehler_differentials(R::Ring; cached::Bool=true)
kaehler_differentials(R::Ring, p::Int; cached::Bool=true)
For `R` a polynomial ring, an affine algebra, or a localization of these
over a `base_ring` ``𝕜`` this returns the module of Kaehler
differentials ``Ω¹(R/𝕜)``, resp. its `p`-th exterior power.
"""
function kaehler_differentials(R::Ring, p::Int; cached::Bool=true)
isone(p) && return kaehler_differentials(R, cached=cached)
cached && haskey(_kaehler_differentials(R), p) && return _kaehler_differentials(R)[p]
result = exterior_power(kaehler_differentials(R, cached=cached), p)[1]
set_attribute!(result, :show, show_kaehler_differentials)
set_attribute!(result, :is_kaehler_differential_module, (R, p))
cached && (_kaehler_differentials(R)[p] = result)
return result
end

@doc raw"""
is_kaehler_differential_module(M::ModuleFP)
Internal method to check whether a module `M` was created as
some ``p``-th exterior power of the Kaehler differentials
``Ω¹(R/𝕜)`` of some ``𝕜``-algebra ``R``.
Returns `(true, R, p)` in the affirmative case and
`(false, base_ring(M), 0)` otherwise.
"""
function is_kaehler_differential_module(M::ModuleFP)
has_attribute(M, :is_kaehler_differential_module) || return false, base_ring(M), 0
R, p = get_attribute(M, :is_kaehler_differential_module)
return true, R, p
end

@doc raw"""
de_rham_complex(R::Ring; cached::Bool=true)
Constructs the relative de Rham complex of a ``𝕜``-algebra `R`
as a `ComplexOfMorphisms`.
"""
function de_rham_complex(R::Ring; cached::Bool=true)
n = ngens(R)
Omega = [kaehler_differentials(R, p, cached=cached) for p in 0:n]
res_maps = [MapFromFunc(Omega[i], Omega[i+1], w->exterior_derivative(w, parent=Omega[i+1])) for i in 1:n]
return ComplexOfMorphisms(typeof(Omega[1]), res_maps, typ=:cochain, seed=0, check=false)
end

# printing of kaehler differentials
function show_kaehler_differentials(io::IO, M::ModuleFP)
success, F, p = is_exterior_power(M)
R = base_ring(F)
if success
if is_unicode_allowed()
print(io, "Ω^$p($R)")
else
print(io, "\\Omega^$p($R)")
end
else
if is_unicode_allowed()
print(io, "Ω^1($R)")
else
print(io, "\\Omega^1($R)")
end
end
end

function show_kaehler_differentials(io::IO, ::MIME"text/html", M::ModuleFP)
success, F, p = is_exterior_power(M)
R = base_ring(F)
io = IOContext(io, :compact => true)
if success
if is_unicode_allowed()
print(io, "Ω^$p($R)")
else
print(io, "\\Omega^$p($R)")
end
else
if is_unicode_allowed()
print(io, "Ω^1($R)")
else
print(io, "\\Omega^1($R)")
end
end
end

# Exterior derivatives
@doc raw"""
exterior_derivative(f::Union{MPolyRingElem, MPolyLocRingElem, MPolyQuoRingElem, MPolyQuoLocRingElem};
parent::ModuleFP=kaehler_differentials(parent(f)))
Compute the exterior derivative of an element ``f`` of a ``𝕜``-algebra `R`
as an element of the `kaehler_differentials` of `R`.
"""
function exterior_derivative(f::Union{MPolyRingElem, MPolyLocRingElem, MPolyQuoRingElem, MPolyQuoLocRingElem};
parent::ModuleFP=kaehler_differentials(parent(f))
)
R = Oscar.parent(f)
n = ngens(R)
dx = gens(parent)
df = sum(derivative(f, i)*dx[i] for i in 1:n; init=zero(parent))
return df
end

@doc raw"""
exterior_derivative(w::ModuleFPElem; parent::ModuleFP=...)
Checks whether `parent(w)` is an exterior power ``Ωᵖ(R/𝕜)`` of the module of
Kaehler differentials of some ``𝕜``-algebra `R` and computes its exterior
derivative in `parent`. If the latter is not specified, it defaults to
``Ωᵖ⁺¹(R/𝕜)``, the `kaehler_differentials(R, p+1)`.
"""
function exterior_derivative(w::ModuleFPElem;
parent::ModuleFP=begin
success, R, p = is_kaehler_differential_module(parent(w))
success || error("not a kaehler differential module")
kaehler_differentials(R, p+1)
end
)
success, R, p = is_kaehler_differential_module(Oscar.parent(w))
M = Oscar.parent(w)
result = zero(parent)
iszero(p) && return exterior_derivative(w[1], parent=parent)
for (i, a) in coordinates(w)
da = exterior_derivative(a)
result = result + wedge(da, M[i], parent=parent)
end
return result
end

function symbols(L::MPolyLocRing)
return symbols(base_ring(L))
end

function change_base_ring(R::Ring, phi::ModuleFPHom{<:ModuleFP, <:ModuleFP, <:Nothing})
dom_res, dom_map = change_base_ring(R, domain(phi))
cod_res, cod_map = change_base_ring(R, codomain(phi))
result = hom(dom_res, cod_res, cod_map.(phi.(gens(domain(phi)))))
return result, dom_map, cod_map
end

function derivative(a::MPolyQuoRingElem, i::Int)
return parent(a)(derivative(lift(a), i))
end
3 changes: 3 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ export cyclic_group
export cyclic_polytope
export cyclic_quotient_singularity
export data
export de_rham_complex
export decide_du_val_singularity
export decomposition_matrix
export decorate
Expand Down Expand Up @@ -508,6 +509,7 @@ export exponent, has_exponent, set_exponent
export exponents
export ext
export extension_field
export exterior_derivative
export exterior_power
export f_vector
export face_fan
Expand Down Expand Up @@ -890,6 +892,7 @@ export johnson_solid
export k_cyclic_polytope
export k_skeleton
export katsura
export kaehler_differentials
export kernel
export klee_minty_cube
export klein_bottle
Expand Down
47 changes: 47 additions & 0 deletions test/Modules/deRhamComplexes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@testset "de Rham complexes of polynomial rings and their localizations" begin
R, (x, y, z, w) = polynomial_ring(QQ, [:x, :y, :z, :w], cached=false)
X = gens(R)

dX = Oscar.exterior_derivative.(X)
@test all(w->Oscar.is_kaehler_differential_module(parent(w))[1], dX)
w = y*dX[1]
@test Oscar.exterior_derivative(w) == Oscar.exterior_derivative(-x*dX[2])
W2_alt = Oscar.kaehler_differentials(R, 2, cached=false)
@test W2_alt === parent(Oscar.exterior_derivative(w, parent=W2_alt))

W0 = Oscar.kaehler_differentials(R, 0)
w = x*W0[1]
@test parent(Oscar.exterior_derivative(w)) === Oscar.kaehler_differentials(R, 1)
W1_alt = Oscar.kaehler_differentials(R, 1, cached=false)
@test W1_alt !== Oscar.kaehler_differentials(R, 1)
@test parent(Oscar.exterior_derivative(w, parent=W1_alt)) === W1_alt

U = powers_of_element(x)
L, loc = localization(R, U)
W = Oscar.de_rham_complex(L)

d1 = map(W, 1)
dX = gens(W[1])
@test d1(L(1//x)*W[1][2]) == -L(1//x^2)*wedge(dX[1], dX[2])

I = ideal(R, R[4])
A, pr = quo(R, I)
WA1 = Oscar.kaehler_differentials(A)
@test iszero(WA1[4])
WA = Oscar.de_rham_complex(A)
@test iszero(WA[4])
@test !iszero(WA[3])
d2 = map(WA, 2)
@test d2(A(x)*WA[2][4]) == WA[3][1]
@test "$(WA[2])" == "$(Oscar.is_unicode_allowed() ? "Ω" : "\\Omega")^2($A)"

I = L(I)
A, pr = quo(L, I)
WA1 = Oscar.kaehler_differentials(A)
@test iszero(WA1[4])
WA = Oscar.de_rham_complex(A)
@test iszero(WA[4])
@test !iszero(WA[3])
d2 = map(WA, 2)
@test d2(A(1//x)*WA[2][4]) == -A(1//x^2)*WA[3][1]
end

0 comments on commit 62a8627

Please sign in to comment.