diff --git a/experimental/LieAlgebras/src/serialization.jl b/experimental/LieAlgebras/src/serialization.jl index e3f8f8cea08..573c3124783 100644 --- a/experimental/LieAlgebras/src/serialization.jl +++ b/experimental/LieAlgebras/src/serialization.jl @@ -240,109 +240,3 @@ end function load_type_params(s::DeserializerState, ::Type{<:LieAlgebraModuleElem}) return load_typed_object(s) end - -############################################################################### -# -# Root systems -# -############################################################################### - -@register_serialization_type RootSystem uses_id - -function save_object(s::SerializerState, R::RootSystem) - save_data_dict(s) do - save_object(s, cartan_matrix(R), :cartan_matrix) - if has_root_system_type(R) - type, type_ordering = root_system_type_with_ordering(R) - save_object(s, type, :type) - if !issorted(type_ordering) # don't save if it's the default - save_object(s, type_ordering, :type_ordering) - end - end - end -end - -function load_object(s::DeserializerState, ::Type{RootSystem}) - cm = load_object(s, Matrix, Int, :cartan_matrix) - R = root_system(cm; check=false, detect_type=false) - if haskey(s, :type) - type = Vector{Tuple{Symbol,Int}}(load_object(s, Vector, (Tuple, [Symbol, Int]), :type)) # coercion needed due to https://github.com/oscar-system/Oscar.jl/issues/3983 - if haskey(s, :type_ordering) - type_ordering = load_object(s, Vector, Int, :type_ordering) - set_root_system_type!(R, type, type_ordering) - else - set_root_system_type!(R, type) - end - end - return R -end - -@register_serialization_type RootSpaceElem uses_params -@register_serialization_type DualRootSpaceElem uses_params - -function save_object(s::SerializerState, r::Union{RootSpaceElem,DualRootSpaceElem}) - save_object(s, _vec(coefficients(r))) -end - -function load_object( - s::DeserializerState, T::Type{<:Union{RootSpaceElem,DualRootSpaceElem}}, R::RootSystem -) - return T(R, load_object(s, Vector, QQ)) -end - -function save_type_params(s::SerializerState, r::Union{RootSpaceElem,DualRootSpaceElem}) - save_data_dict(s) do - save_object(s, encode_type(typeof(r)), :name) - rs_x = root_system(r) - rs_ref = save_as_ref(s, rs_x) - save_object(s, rs_ref, :params) - end -end - -function load_type_params( - s::DeserializerState, ::Type{<:Union{RootSpaceElem,DualRootSpaceElem}} -) - return load_typed_object(s) -end - -############################################################################### -# -# Weyl groups -# -############################################################################### - -@register_serialization_type WeylGroup uses_id - -function save_object(s::SerializerState, W::WeylGroup) - save_data_dict(s) do - save_typed_object(s, root_system(W), :root_system) - end -end - -function load_object(s::DeserializerState, ::Type{WeylGroup}) - R = load_typed_object(s, :root_system) - return weyl_group(R) -end - -@register_serialization_type WeylGroupElem uses_params - -function save_object(s::SerializerState, x::WeylGroupElem) - save_object(s, word(x)) -end - -function load_object(s::DeserializerState, ::Type{WeylGroupElem}, W::WeylGroup) - return W(load_object(s, Vector, UInt8); normalize=false) -end - -function save_type_params(s::SerializerState, x::WeylGroupElem) - save_data_dict(s) do - save_object(s, encode_type(typeof(x)), :name) - parent_x = parent(x) - parent_ref = save_as_ref(s, parent_x) - save_object(s, parent_ref, :params) - end -end - -function load_type_params(s::DeserializerState, ::Type{WeylGroupElem}) - return load_typed_object(s) -end diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl deleted file mode 100644 index 5e70ef713b1..00000000000 --- a/experimental/LieAlgebras/test/RootSystem-test.jl +++ /dev/null @@ -1,107 +0,0 @@ -@testset "LieAlgebras.RootSystem" begin - @testset "property tests (only Serialization)" begin - - # merge this again with `root_system_property_tests` from test/LieTheory/RootSystem.jl once this is moved to src - function root_system_property_tests(R::RootSystem, rk::Int, npositive_roots::Int) - @testset "Serialization" begin - mktempdir() do path - test_save_load_roundtrip(path, R) do loaded - # nothing, cause `R === loaded` anyway - end - - if n_roots(R) >= 1 - r = positive_root(R, n_positive_roots(R)) - test_save_load_roundtrip(path, r) do loaded - @test root_system(loaded) === R - @test coefficients(loaded) == coefficients(r) - end - end - - test_save_load_roundtrip(path, positive_roots(R)) do loaded - @test length(loaded) == n_positive_roots(R) - @test all( - coefficients(loaded[i]) == coefficients(root(R, i)) for - i in 1:n_positive_roots(R) - ) - end - end - end - end - - @testset "rk 0" begin - R = root_system(zero_matrix(ZZ, 0, 0)) - root_system_property_tests(R, 0, 0) - end - - @testset "A_$n" for n in [1, 2, 6] - R = root_system(:A, n) - root_system_property_tests(R, n, binomial(n + 1, 2)) - end - - @testset "B_$n" for n in [2, 3, 6] - R = root_system(:B, n) - root_system_property_tests(R, n, n^2) - end - - @testset "C_$n" for n in [2, 3, 6] - R = root_system(:C, n) - root_system_property_tests(R, n, n^2) - end - - @testset "D_$n" for n in [4, 6] - R = root_system(:D, n) - root_system_property_tests(R, n, n^2 - n) - end - - @testset "E_6" begin - R = root_system(:E, 6) - root_system_property_tests(R, 6, 36) - end - - @testset "E_7" begin - R = root_system(:E, 7) - root_system_property_tests(R, 7, 63) - end - - @testset "E_8" begin - R = root_system(:E, 8) - root_system_property_tests(R, 8, 120) - end - - @testset "F_4" begin - R = root_system(:F, 4) - root_system_property_tests(R, 4, 24) - end - - @testset "G_2" begin - R = root_system(:G, 2) - root_system_property_tests(R, 2, 6) - end - - @testset "something mixed 1" begin - cm = cartan_matrix((:A, 3), (:C, 3), (:E, 6), (:G, 2)) - for _ in 1:50 - i, j = rand(1:nrows(cm), 2) - if i != j - swap_rows!(cm, i, j) - swap_cols!(cm, i, j) - end - end - R = root_system(cm) - root_system_property_tests(R, 3 + 3 + 6 + 2, binomial(3 + 1, 2) + 3^2 + 36 + 6) - end - - @testset "something mixed 2" begin - cm = cartan_matrix((:F, 4), (:B, 2), (:E, 7), (:G, 2)) - for _ in 1:50 - i, j = rand(1:nrows(cm), 2) - if i != j - swap_rows!(cm, i, j) - swap_cols!(cm, i, j) - end - end - R = root_system(cm) - root_system_property_tests(R, 4 + 2 + 7 + 2, 24 + 2^2 + 63 + 6) - end - end -end diff --git a/experimental/LieAlgebras/test/WeylGroup-test.jl b/experimental/LieAlgebras/test/WeylGroup-test.jl index 2e36905c4c0..1b8b77caf52 100644 --- a/experimental/LieAlgebras/test/WeylGroup-test.jl +++ b/experimental/LieAlgebras/test/WeylGroup-test.jl @@ -118,62 +118,4 @@ end end end - - @testset "Serialization" begin - mktempdir() do path - @testset "simple saving and loading" begin - W = weyl_group((:A, 2), (:B, 4)) - - test_save_load_roundtrip(path, W) do loaded - # nothing, cause `W === loaded` anyway - end - - x = rand(W) - test_save_load_roundtrip(path, x) do loaded - @test parent(loaded) === W - @test word(loaded) == word(x) - end - - test_save_load_roundtrip(path, gens(W)) do loaded - @test length(loaded) == ngens(W) - @test all( - word(loaded[i]) == word(gen(W, i)) for i in 1:ngens(W) - ) - end - end - - @testset "cyclic reference between R and W survives" begin - Oscar.reset_global_serializer_state() - - R_filename = joinpath(path, "R.mrdi") - W_filename = joinpath(path, "W.mrdi") - - R = root_system(:D, 5) - W = weyl_group(R) - - save(R_filename, R) - save(W_filename, W) - - Oscar.reset_global_serializer_state() - - loaded_R = load(R_filename) - loaded_W = load(W_filename) - - @test loaded_R === root_system(loaded_W) - @test loaded_W === weyl_group(loaded_R) - - loaded_R = loaded_W = nothing # unset all references - - Oscar.reset_global_serializer_state() - - loaded_W = load(W_filename) - loaded_R = load(R_filename) - - @test loaded_R === root_system(loaded_W) - @test loaded_W === weyl_group(loaded_R) - - loaded_R = loaded_W = nothing # unset all references - end - end - end end diff --git a/src/Serialization/LieTheory.jl b/src/Serialization/LieTheory.jl new file mode 100644 index 00000000000..2d06aa6769f --- /dev/null +++ b/src/Serialization/LieTheory.jl @@ -0,0 +1,147 @@ +############################################################################### +# +# Root systems +# +############################################################################### + +@register_serialization_type RootSystem uses_id + +function save_object(s::SerializerState, R::RootSystem) + save_data_dict(s) do + save_object(s, cartan_matrix(R), :cartan_matrix) + if has_root_system_type(R) + type, type_ordering = root_system_type_with_ordering(R) + save_object(s, type, :type) + if !issorted(type_ordering) # don't save if it's the default + save_object(s, type_ordering, :type_ordering) + end + end + end +end + +function load_object(s::DeserializerState, ::Type{RootSystem}) + cm = load_object(s, Matrix, Int, :cartan_matrix) + R = root_system(cm; check=false, detect_type=false) + if haskey(s, :type) + type = Vector{Tuple{Symbol,Int}}(load_object(s, Vector, (Tuple, [Symbol, Int]), :type)) # coercion needed due to https://github.com/oscar-system/Oscar.jl/issues/3983 + if haskey(s, :type_ordering) + type_ordering = load_object(s, Vector, Int, :type_ordering) + set_root_system_type!(R, type, type_ordering) + else + set_root_system_type!(R, type) + end + end + return R +end + +@register_serialization_type RootSpaceElem uses_params +@register_serialization_type DualRootSpaceElem uses_params + +function save_object(s::SerializerState, r::Union{RootSpaceElem,DualRootSpaceElem}) + save_object(s, _vec(coefficients(r))) +end + +function load_object( + s::DeserializerState, T::Type{<:Union{RootSpaceElem,DualRootSpaceElem}}, R::RootSystem +) + return T(R, load_object(s, Vector, QQ)) +end + +function save_type_params(s::SerializerState, r::Union{RootSpaceElem,DualRootSpaceElem}) + save_data_dict(s) do + save_object(s, encode_type(typeof(r)), :name) + rs_x = root_system(r) + rs_ref = save_as_ref(s, rs_x) + save_object(s, rs_ref, :params) + end +end + +function load_type_params( + s::DeserializerState, ::Type{<:Union{RootSpaceElem,DualRootSpaceElem}} +) + return load_typed_object(s) +end + +############################################################################### +# +# Weight lattices +# +############################################################################### + +@register_serialization_type WeightLattice uses_id + +function save_object(s::SerializerState, P::WeightLattice) + save_data_dict(s) do + save_typed_object(s, root_system(P), :root_system) + end +end + +function load_object(s::DeserializerState, ::Type{WeightLattice}) + R = load_typed_object(s, :root_system) + return weight_lattice(R) +end + +@register_serialization_type WeightLatticeElem uses_params + +function save_object(s::SerializerState, w::WeightLatticeElem) + save_object(s, _vec(coefficients(w))) +end + +function load_object(s::DeserializerState, ::Type{WeightLatticeElem}, P::WeightLattice) + return WeightLatticeElem(P, load_object(s, Vector, ZZ)) +end + +function save_type_params(s::SerializerState, w::WeightLatticeElem) + save_data_dict(s) do + save_object(s, encode_type(typeof(w)), :name) + parent_w = parent(w) + parent_ref = save_as_ref(s, parent_w) + save_object(s, parent_ref, :params) + end +end + +function load_type_params(s::DeserializerState, ::Type{WeightLatticeElem}) + return load_typed_object(s) +end + +############################################################################### +# +# Weyl groups +# +############################################################################### + +@register_serialization_type WeylGroup uses_id + +function save_object(s::SerializerState, W::WeylGroup) + save_data_dict(s) do + save_typed_object(s, root_system(W), :root_system) + end +end + +function load_object(s::DeserializerState, ::Type{WeylGroup}) + R = load_typed_object(s, :root_system) + return weyl_group(R) +end + +@register_serialization_type WeylGroupElem uses_params + +function save_object(s::SerializerState, x::WeylGroupElem) + save_object(s, word(x)) +end + +function load_object(s::DeserializerState, ::Type{WeylGroupElem}, W::WeylGroup) + return W(load_object(s, Vector, UInt8); normalize=false) +end + +function save_type_params(s::SerializerState, x::WeylGroupElem) + save_data_dict(s) do + save_object(s, encode_type(typeof(x)), :name) + parent_x = parent(x) + parent_ref = save_as_ref(s, parent_x) + save_object(s, parent_ref, :params) + end +end + +function load_type_params(s::DeserializerState, ::Type{WeylGroupElem}) + return load_typed_object(s) +end diff --git a/src/Serialization/main.jl b/src/Serialization/main.jl index d9624be77aa..fff1110bf73 100644 --- a/src/Serialization/main.jl +++ b/src/Serialization/main.jl @@ -475,6 +475,7 @@ include("TropicalGeometry.jl") include("QuadForm.jl") include("GAP.jl") include("Groups.jl") +include("LieTheory.jl") include("Upgrades/main.jl") diff --git a/test/Serialization/LieTheory.jl b/test/Serialization/LieTheory.jl new file mode 100644 index 00000000000..29363274698 --- /dev/null +++ b/test/Serialization/LieTheory.jl @@ -0,0 +1,180 @@ +@testset "LieTheory" begin + mktempdir() do path + @testset "RootSystem" begin + for R in [ + root_system(zero_matrix(ZZ, 0, 0)), # rk 0 + root_system(:A, 1), + root_system(:A, 6), + root_system(:B, 2), + root_system(:C, 5), + root_system(:D, 4), + root_system(:E, 6), + root_system(:F, 4), + root_system(:G, 2), + begin # something mixed + cm = cartan_matrix((:A, 3), (:C, 3), (:E, 6), (:G, 2)) + for _ in 1:50 + i, j = rand(1:nrows(cm), 2) + if i != j + swap_rows!(cm, i, j) + swap_cols!(cm, i, j) + end + end + root_system(cm) + end, + ] + test_save_load_roundtrip(path, R) do loaded + # nothing, cause `R === loaded` anyway + end + + if rank(R) >= 1 + r = positive_root(R, n_positive_roots(R)) + test_save_load_roundtrip(path, r) do loaded + @test root_system(loaded) === R + @test coefficients(loaded) == coefficients(r) + end + + cr = positive_coroot(R, n_positive_roots(R)) + test_save_load_roundtrip(path, cr) do loaded + @test root_system(loaded) === R + @test coefficients(loaded) == coefficients(cr) + end + end + + test_save_load_roundtrip(path, positive_roots(R)) do loaded + @test length(loaded) == n_positive_roots(R) + @test all( + coefficients(loaded[i]) == coefficients(positive_root(R, i)) for + i in 1:n_positive_roots(R) + ) + end + + test_save_load_roundtrip(path, negative_coroots(R)) do loaded + @test length(loaded) == n_positive_roots(R) + @test all( + coefficients(loaded[i]) == coefficients(negative_coroot(R, i)) for + i in 1:n_positive_roots(R) + ) + end + end + end + + @testset "WeightLattice" begin + @testset "simple saving and loading" begin + for R in [ + root_system(zero_matrix(ZZ, 0, 0)), # rk 0 + root_system((:A, 2), (:B, 4)), + ] + P = weight_lattice(R) + + test_save_load_roundtrip(path, P) do loaded + # nothing, cause `P === loaded` anyway + end + + w = WeightLatticeElem(P, [rand(ZZ, -10:10) for _ in 1:rank(P)]) + test_save_load_roundtrip(path, w) do loaded + @test parent(loaded) === P + @test coefficients(loaded) == coefficients(w) + end + + test_save_load_roundtrip(path, gens(P)) do loaded + @test length(loaded) == rank(P) + @test all(coefficients(loaded[i]) == coefficients(gen(P, i)) for i in 1:rank(R)) + end + end + end + + @testset "cyclic reference between R and P survives" begin + Oscar.reset_global_serializer_state() + + R_filename = joinpath(path, "R.mrdi") + P_filename = joinpath(path, "P.mrdi") + + R = root_system(:D, 5) + P = weight_lattice(R) + + save(R_filename, R) + save(P_filename, P) + + Oscar.reset_global_serializer_state() + + loaded_R = load(R_filename) + loaded_P = load(P_filename) + + @test loaded_R === root_system(loaded_P) + @test loaded_P === weight_lattice(loaded_R) + + loaded_R = loaded_P = nothing # unset all references + + Oscar.reset_global_serializer_state() + + loaded_P = load(P_filename) + loaded_R = load(R_filename) + + @test loaded_R === root_system(loaded_P) + @test loaded_P === weight_lattice(loaded_R) + + loaded_R = loaded_P = nothing # unset all references + end + end + + @testset "WeylGroup" begin + @testset "simple saving and loading" begin + for W in [ + weyl_group(zero_matrix(ZZ, 0, 0)), # rk 0 + weyl_group((:A, 2), (:B, 4)), + ] + test_save_load_roundtrip(path, W) do loaded + # nothing, cause `W === loaded` anyway + end + + x = rand(W) + test_save_load_roundtrip(path, x) do loaded + @test parent(loaded) === W + @test word(loaded) == word(x) + end + + test_save_load_roundtrip(path, gens(W)) do loaded + @test length(loaded) == ngens(W) + @test all( + word(loaded[i]) == word(gen(W, i)) for i in 1:ngens(W) + ) + end + end + end + + @testset "cyclic reference between R and W survives" begin + Oscar.reset_global_serializer_state() + + R_filename = joinpath(path, "R.mrdi") + W_filename = joinpath(path, "W.mrdi") + + R = root_system(:D, 5) + W = weyl_group(R) + + save(R_filename, R) + save(W_filename, W) + + Oscar.reset_global_serializer_state() + + loaded_R = load(R_filename) + loaded_W = load(W_filename) + + @test loaded_R === root_system(loaded_W) + @test loaded_W === weyl_group(loaded_R) + + loaded_R = loaded_W = nothing # unset all references + + Oscar.reset_global_serializer_state() + + loaded_W = load(W_filename) + loaded_R = load(R_filename) + + @test loaded_R === root_system(loaded_W) + @test loaded_W === weyl_group(loaded_R) + + loaded_R = loaded_W = nothing # unset all references + end + end + end +end