oscar-system / Oscar.jl

A comprehensive open source computer algebra system for computations in algebra, geometry, and number theory.
https://www.oscar-system.org
Other
339 stars 120 forks source link

Serialization problems with cyclotomic fields #1719

Closed rogeliam closed 1 year ago

rogeliam commented 1 year ago
  1. The functions save/load do not save correctly if the ground field was a cyclotomic field.
julia> K,ζ=cyclotomic_field(6)
(Cyclotomic field of order 6, z_6)

julia> x=ζ+1
z_6 + 1

julia> save("varx.jl",x)
2117

julia> y=load("varx.jl")
z_6 + 1

julia> parent(x)
Cyclotomic field of order 6

julia> parent(y)
Number field over Rational Field with defining polynomial _$^2 - _$ + 1

julia> z=load("varx.jl",typeof(x))
z_6 + 1

julia> parent(z)
Number field over Rational Field with defining polynomial _$^2 - _$ + 1
  1. Furthermore specifying a parent with matrices does not seem to be supported right now.
julia> K,ζ=cyclotomic_field(6)
(Cyclotomic field of order 6, z_6)

julia> T=matrix(K,2,2,[1 ζ; ζ ζ^2])
[  1       z_6]
[z_6   z_6 - 1]

julia> parent(T)
Matrix Space of 2 rows and 2 columns over K

julia> save("testsave.jl",T)
4036

julia> TT=load("testsave.jl")
[  1       z_6]
[z_6   z_6 - 1]

julia> parent(TT)
Matrix Space of 2 rows and 2 columns over Number field over Rational Field with defining polynomial _$^2 - _$ + 1

julia> T*TT
[    z_6   z_6 - 1]
[z_6 - 1        -1]

julia> TT[1,2]*T[1,2]
ERROR: no common parent known
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] force_op(::typeof(*), ::Type{Val{true}}, ::nf_elem, ::Vararg{nf_elem, N} where N)
   @ Hecke ~/.julia/packages/Hecke/KyG8x/src/NumField/NfAbs/NfAbs.jl:1224
 [3] force_op
   @ ~/.julia/packages/AbstractAlgebra/ZmWFo/src/AbstractAlgebra.jl:318 [inlined]
 [4] *(a::nf_elem, b::nf_elem)
   @ Nemo ~/.julia/packages/Nemo/syxmO/src/antic/nf_elem.jl:337
 [5] top-level scope
   @ REPL[60]:1

julia> TTT=load("testsave.jl",parent=parent(T))
ERROR: MethodError: no method matching load_internal_with_parent(::Oscar.DeserializerState, ::Type{MatElem}, ::Dict{Symbol, Any}, ::AbstractAlgebra.Generic.MatSpace{nf_elem})
Closest candidates are:
  load_internal_with_parent(::Oscar.DeserializerState, ::Type{Vector{T} where T}, ::Dict, ::Any) at /home/rogel/.julia/packages/Oscar/W7C5G/src/Serialization/containers.jl:35
  load_internal_with_parent(::Oscar.DeserializerState, ::Type{Vector{T}}, ::Dict, ::Any) where T at /home/rogel/.julia/packages/Oscar/W7C5G/src/Serialization/containers.jl:20
  load_internal_with_parent(::Oscar.DeserializerState, ::Type{var"#s262"} where var"#s262"<:Union{fmpz_laurent_series, Union{AbstractAlgebra.Generic.LaurentSeriesFieldElem{T}, AbstractAlgebra.Generic.LaurentSeriesRingElem{T}} where T<:RingElement}, ::Dict, ::Any) at /home/rogel/.julia/packages/Oscar/W7C5G/src/Serialization/Rings.jl:457
  ...
Stacktrace:
 [1] load_type_dispatch(s::Oscar.DeserializerState, ::Type{MatElem}, dict::Dict{Symbol, Any}; parent::AbstractAlgebra.Generic.MatSpace{nf_elem})
   @ Oscar ~/.julia/packages/Oscar/W7C5G/src/Serialization/main.jl:150
 [2] load_unknown_type(s::Oscar.DeserializerState, dict::Dict{Symbol, Any}; parent::AbstractAlgebra.Generic.MatSpace{nf_elem}, check_namespace::Bool)
   @ Oscar ~/.julia/packages/Oscar/W7C5G/src/Serialization/main.jl:181
 [3] load(io::IOStream; parent::AbstractAlgebra.Generic.MatSpace{nf_elem})
   @ Oscar ~/.julia/packages/Oscar/W7C5G/src/Serialization/main.jl:264
 [4] #3417
   @ ~/.julia/packages/Oscar/W7C5G/src/Serialization/main.jl:269 [inlined]
 [5] open(f::Oscar.var"#3417#3418"{AbstractAlgebra.Generic.MatSpace{nf_elem}}, args::String; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ Base ./io.jl:330
 [6] open
   @ ./io.jl:328 [inlined]
 [7] #load#3416
   @ ~/.julia/packages/Oscar/W7C5G/src/Serialization/main.jl:268 [inlined]
 [8] top-level scope
   @ REPL[61]:1

Here it is notable, that multiplication of T and TT does work, but multiplication of the entries does not work.

System (please complete the following information): Please paste the output of Oscar.versioninfo(full=true) below. If this does not work, please paste the output of Julia's versioninfo() and your Oscar version.

julia> Oscar.versioninfo(full=true)
OSCAR version 0.11.0
  combining:
    AbstractAlgebra.jl   v0.27.6
    GAP.jl               v0.8.5
    Hecke.jl             v0.15.8
    Nemo.jl              v0.32.4
    Polymake.jl          v0.8.2
    Singular.jl          v0.14.0
  building on:
    Antic_jll               v0.201.500+0
    Arb_jll                 v200.2300.0+0
    Calcium_jll             v0.401.100+0
    FLINT_jll               v200.900.1+0
    GAP_jll                 v400.1192.2+1
    Singular_jll            v403.101.400+0
    libpolymake_julia_jll   v0.8.3+0
    libsingular_julia_jll   v0.27.0+0
    polymake_jll            v400.700.1+1
See `]st -m` for a full list of dependencies.

Julia Version 1.6.2
Commit 1b93d53fc4 (2021-07-14 15:36 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-11.0.1 (ORCJIT, skylake)
Official https://julialang.org/ release

...
thofma commented 1 year ago

Just a remark for @antonydellavecchia and the other developers

The functions save/load do not save correctly if the ground field was a cyclotomic field.

It is the 'same' field, but just printed differently. The special printing comes from a property stored in the attributes of the objects (aka set_attribute!/get_attribute). While I do not think that consistent printing should be guaranteed, it raises the question about handling this additional data in general. Have there already been some ideas/decisions in this regard?

antonydellavecchia commented 1 year ago

I don't think there has been any decisions made. I think some people have thought about it a bit? I guess the issue is that deciding to store attributes should be left to the user. Maybe there are some that should be stored regardless? maybe if an ideal is a groebner basis or not? From what I gather storing the field with a cyclotomic attribute or not doesn't have any effect on the type? so everything should work accordingly?

But ideally it would be nice to store this if the users wants. I guess we would try to offer an interface where the user can list the attributes that they would like to store.

fingolfin commented 1 year ago

@thofma I think this is a type-by-type discussion: we definitely want to serialize all "essential" data; if that means serializing some of the attribute, so be it. I see no fundamental problem in having logic of the kind if attribute X is present then serialize it and matching while deserializing.

(Perhaps trickier is what to do about data that is cached for performance reasons; do we want to store that? probably not in general, but sometimes it might be useful? how would one specify that? or perhaps this shouldn't be done and restoring special cached information is about the code calling the serialization layer?)

thofma commented 1 year ago

It is tricky to have an interface where a user can choose the attributes to be stored. I think we made sure that attributes are not part of the API of objects. For example, how would a user know, that the information, that an ideal is prime (just an example) is an attribute, which could be serialized/deserialized. So I think an interface where specific attributes are specified will be hard. Or maybe I am missing something.