Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first attempts at writing the serializers for the new types PhylogeneticModel and GroupBasedPhylogeneticModel #4010

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions experimental/AlgebraicStatistics/src/AlgebraicStatistics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ include("PhylogeneticModels.jl")
include("PhylogeneticAuxiliary.jl")
include("PhylogeneticParametrization.jl")

include("serialization.jl")

#export models
export cavender_farris_neyman_model
export jukes_cantor_model
Expand Down
12 changes: 6 additions & 6 deletions experimental/AlgebraicStatistics/src/PhylogeneticModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct PhylogeneticModel
graph::Graph{Directed}
n_states::Int
prob_ring::MPolyRing{QQFieldElem}
root_distr::Vector{Any}
root_distr::Vector
trans_matrices::Dict{Edge, MatElem{QQMPolyRingElem}}
end

Expand Down Expand Up @@ -158,7 +158,7 @@ Return the distribution of the random variable at the root of the tree specifyin
julia> pm = jukes_cantor_model(graph_from_edges(Directed,[[4,1],[4,2],[4,3]]));

julia> root_distribution(pm)
4-element Vector{Any}:
4-element Vector{QQFieldElem}:
1//4
1//4
1//4
Expand Down Expand Up @@ -247,7 +247,7 @@ function cavender_farris_neyman_model(graph::Graph{Directed})
ne = n_edges(graph)
R, list_a, list_b = polynomial_ring(QQ, :a => 1:ne, :b => 1:ne; cached=false)

root_distr = repeat([1//ns], outer = ns)
root_distr = repeat([QQ(1,ns)], outer = ns)
edgs = sort_edges(graph)
matrices = Dict{Edge, MatElem}(e => matrix(R, [
a b
Expand Down Expand Up @@ -288,7 +288,7 @@ function jukes_cantor_model(graph::Graph{Directed})
ne = n_edges(graph)
R, list_a, list_b = polynomial_ring(QQ, :a => 1:ne, :b => 1:ne; cached=false)

root_distr = repeat([1//ns], outer = ns)
root_distr = repeat([QQ(1, ns)], outer = ns)
edgs = sort_edges(graph)
matrices = Dict{Edge, MatElem}(e => matrix(R, [
a b b b
Expand Down Expand Up @@ -332,7 +332,7 @@ function kimura2_model(graph::Graph{Directed})
ne = n_edges(graph)
R, list_a, list_b, list_c = polynomial_ring(QQ, :a => 1:ne, :b => 1:ne, :c => 1:ne; cached=false)

root_distr = repeat([1//ns], outer = ns)
root_distr = repeat([QQ(1,ns)], outer = ns)
edgs = sort_edges(graph)
matrices = Dict{Edge, MatElem}(e => matrix(R, [
a b c b
Expand Down Expand Up @@ -375,7 +375,7 @@ function kimura3_model(graph::Graph{Directed})
ne = n_edges(graph)
R, list_a, list_b , list_c, list_d= polynomial_ring(QQ, :a => 1:ne, :b => 1:ne, :c => 1:ne, :d => 1:ne; cached=false)

root_distr = repeat([1//ns], outer = ns)
root_distr = repeat([QQ(1,ns)], outer = ns)
edgs = sort_edges(graph)
matrices = Dict{Edge, MatElem}(e => matrix(R, [
a b c d
Expand Down
40 changes: 40 additions & 0 deletions experimental/AlgebraicStatistics/src/serialization.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@register_serialization_type PhylogeneticModel
@register_serialization_type GroupBasedPhylogeneticModel

function save_object(s::SerializerState, pm::PhylogeneticModel)
save_data_dict(s) do
save_typed_object(s, graph(pm), :tree)
save_object(s, number_states(pm), :states)
save_typed_object(s, probability_ring(pm), :probability_ring)
save_typed_object(s, root_distribution(pm), :root_distribution)
save_typed_object(s, transition_matrices(pm), :transition_matrices)
end
end

function save_object(s::SerializerState, pm::GroupBasedPhylogeneticModel)
save_data_dict(s) do
save_typed_object(s, phylogenetic_model(pm), :phylomodel)
save_typed_object(s, fourier_ring(pm), :fourier_ring)
save_typed_object(s, fourier_parameters(pm), :fourier_params)
save_typed_object(s, group_of_model(pm), :group)
end
end

function load_object(s::DeserializerState, g::Type{PhylogeneticModel})
graph = load_typed_object(s, :tree)
n_states = load_object(s, Int64, :states)
prob_ring = load_typed_object(s, :probability_ring)
root_distr = load_typed_object(s, :root_distribution)
trans_matrices = load_typed_object(s, :transition_matrices)

return PhylogeneticModel(graph, n_states, prob_ring, root_distr, trans_matrices)
end

function load_object(s::DeserializerState, g::Type{GroupBasedPhylogeneticModel})
phylomodel = load_typed_object(s, :phylomodel)
fourier_ring = load_typed_object(s, :fourier_ring)
fourier_params = load_typed_object(s, :fourier_params)
group = load_typed_object(s, :group)

return GroupBasedPhylogeneticModel(phylomodel, fourier_ring, fourier_params, group)
end
47 changes: 47 additions & 0 deletions experimental/AlgebraicStatistics/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ end
@testset "Graphical Models tests" begin

tree = graph_from_edges(Directed,[[4,1],[4,2],[4,3]])
group_based_components = [number_states, probability_ring, root_distribution, transition_matrices, fourier_ring, fourier_parameters, group_of_model]

@testset "cavender_farris_neyman_model" begin
model = cavender_farris_neyman_model(tree)
Expand All @@ -40,6 +41,15 @@ end
# group of the model
G = group_of_model(model)
@test is_isomorphic(unique(parent.(G))[1], abelian_group(2))
# serialization working?
mktempdir() do path
test_save_load_roundtrip(path, model) do loaded
for component in group_based_components
@test component(model) == component(loaded)
@test incidence_matrix(graph(model)) == incidence_matrix(graph(loaded))
end
end
end
end

@testset "Jukes Cantor" begin
Expand All @@ -66,6 +76,15 @@ end
#group of the model
G = group_of_model(model)
@test is_isomorphic(unique(parent.(G))[1], abelian_group(2,2))
# serialization working?
mktempdir() do path
test_save_load_roundtrip(path, model) do loaded
for component in group_based_components
@test component(model) == component(loaded)
@test incidence_matrix(graph(model)) == incidence_matrix(graph(loaded))
end
end
end
end

@testset "kimura2_model" begin
Expand All @@ -92,6 +111,15 @@ end
# group of the model
G = group_of_model(model)
@test is_isomorphic(unique(parent.(G))[1], abelian_group(2,2))
# serialization working?
mktempdir() do path
test_save_load_roundtrip(path, model) do loaded
for component in group_based_components
@test component(model) == component(loaded)
@test incidence_matrix(graph(model)) == incidence_matrix(graph(loaded))
end
end
end
end

@testset "kimura3_model" begin
Expand All @@ -118,6 +146,15 @@ end
# group of the model
G = group_of_model(model)
@test is_isomorphic(unique(parent.(G))[1], abelian_group(2,2))
# serialization working?
mktempdir() do path
test_save_load_roundtrip(path, model) do loaded
for component in group_based_components
@test component(model) == component(loaded)
@test incidence_matrix(graph(model)) == incidence_matrix(graph(loaded))
end
end
end
end

@testset "general_markov_model" begin
Expand All @@ -137,6 +174,16 @@ end
@test tr_mat[Edge(4,1)] isa AbstractAlgebra.Generic.MatSpaceElem{QQMPolyRingElem}
# generators of the polynomial ring
@test length(gens(model.prob_ring)) == 148
# serialization working?
gmm_components = [number_states, probability_ring, root_distribution, transition_matrices]
mktempdir() do path
test_save_load_roundtrip(path, model) do loaded
for component in gmm_components
@test component(model) == component(loaded)
@test incidence_matrix(graph(model)) == incidence_matrix(graph(loaded))
end
end
end
end

@testset "affine models" begin
Expand Down
12 changes: 12 additions & 0 deletions src/Serialization/Combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ using JSON
###############################################################################
@register_serialization_type Graph{Directed} "Graph{Directed}"
@register_serialization_type Graph{Undirected} "Graph{Undirected}"
@register_serialization_type Edge

function save_object(s::SerializerState, g::Graph{T}) where T <: Union{Directed, Undirected}
smallobject = pm_object(g)
Expand All @@ -19,6 +20,17 @@ function load_object(s::DeserializerState, g::Type{Graph{T}}) where T <: Union{D
return g(smallobj)
end

function save_object(s::SerializerState, e::Edge)
save_data_array(s) do
save_object(s, src(e))
save_object(s, dst(e))
end
end

function load_object(s::DeserializerState, e::Type{Edge})
return Edge(load_object(s, Int, 1), load_object(s, Int, 2))
end

###############################################################################
## Matroid
###############################################################################
Expand Down
19 changes: 12 additions & 7 deletions src/Serialization/containers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,9 @@ function load_type_params(s::DeserializerState, ::Type{<:Dict})
params_dict = Dict{Symbol, Any}()
for (k, _) in s.obj
load_node(s, k) do _
println(k)
value_type = decode_type(s)

if serialize_with_params(value_type)
params_dict[k] = Dict{Symbol, Any}(
type_key => value_type,
Expand Down Expand Up @@ -413,24 +414,28 @@ function load_object(s::DeserializerState, ::Type{<:Dict}, params::Dict{Symbol,

if key_type == Int
key = parse(Int, string(k))
elseif haskey(params, :key_params) # type is not Int, String or Symbol
elseif key_type <: Union{Symbol, String}
key = key_type(k)
elseif serialize_with_params(key_type)
load_node(s, i) do _
# 1 is for first entry of tuple which is the key in this case
key = load_object(s, key_type, params[:key_params], 1)
end
else
key = key_type(k)
else
load_node(s,i) do _
key = load_object(s, key_type, 1)
end
end

if value_type != Any
if serialize_with_params(value_type)
if haskey(params, :key_params) # key type is not Int, String or Symbol
if key_type <: Union{Symbol, String}
dict[key] = load_object(s, value_type, params[:value_params], k)
else
load_node(s, i) do _
# 2 is for second entry of tuple which is the value in this case
dict[key] = load_object(s, value_type, params[:value_params], 2)
end
else
dict[key] = load_object(s, value_type, params[:value_params], k)
end
else
if haskey(params, :key_params) # key type is not Int, String or Symbol
Expand Down
Loading