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

JSON ACSetTransformations #865

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/categorical_algebra/CategoricalAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ include("Chase.jl")
include("FunctorialDataMigrations.jl")
include("StructuredCospans.jl")
include("Slices.jl")
include("JSONCSetTransformations.jl")

@reexport using .Categories
@reexport using .FinCats
Expand All @@ -43,4 +44,6 @@ include("Slices.jl")
@reexport using .StructuredCospans
@reexport using .Slices

@reexport using .JSONCSetTransformations

end
114 changes: 114 additions & 0 deletions src/categorical_algebra/JSONCSetTransformations.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
""" JSON serialization of acset transformations.
"""
module JSONCSetTransformations
export generate_json_fin_function, parse_json_fin_function,
read_json_fin_function, write_json_fin_function,
generate_json_acset_transformation, parse_json_acset_transformation,
read_json_acset_transformation, write_json_acset_transformation

import JSON
using DataStructures: OrderedDict

using ..FinSets, ..CSets

# ACSetTransformation serialization
#####################

""" Generate JSON-able object representing a FinFunction.

Inverse to [`parse_json_fin_function`](@ref).
"""
function generate_json_fin_function(F::FinFunction)
OrderedDict{Symbol,Any}(
:dom => dom( F),
:codom => codom( F),
lukem12345 marked this conversation as resolved.
Show resolved Hide resolved
:map => collect(F))
end

""" Serialize a FinFunction object to a JSON file.

Inverse to [`read_json_fin_function`](@ref).
"""
function write_json_fin_function(x::FinFunction, fname::AbstractString)
open(fname, "w") do f
write(f, JSON.json(generate_json_fin_function(x)))
end
end

function parse_json_fin_function(input::AbstractDict)
FinFunction(
Int.(input["map"]),
input["dom"]["n"],
input["codom"]["n"])
end

""" Deserialize a FinFunction object from a JSON file.

Inverse to [`write_json_fin_function`](@ref).
"""
function read_json_fin_function(fname::AbstractString)
parse_json_fin_function(JSON.parsefile(fname))
end

""" Generate JSON-able object representing an ACSetTransformation.

Inverse to [`parse_json_acset_transformation`](@ref).
"""
function generate_json_acset_transformation(X::ACSetTransformation)
OrderedDict{Symbol,Any}(
:dom => (generate_json_acset ∘ dom)(X),
:codom => (generate_json_acset ∘ codom)(X),
:components => OrderedDict{Symbol,Any}(
Iterators.map((keys ∘ components)(X), (values ∘ components)(X)) do k,v
k , k ∈ (attrtypes ∘ acset_schema ∘ dom)(X) ?
# TODO: Support VarFunctions that are not empty.
"TODO: VarFunctions are current not supported." :
generate_json_fin_function(v)
end))
end

""" Serialize an ACSetTransformation object to a JSON file.

Inverse to [`read_json_acset_transformation`](@ref).
"""
function write_json_acset_transformation(x::ACSetTransformation, fname::AbstractString)
open(fname, "w") do f
write(f, JSON.json(generate_json_acset_transformation(x)))
end
end

""" Parse JSON-able object or JSON string representing an ACSetTransformation.

Inverse to [`generate_json_acset_transformation`](@ref).
"""
parse_json_acset_transformation(cons, input::AbstractString) =
parse_json_acset_transformation(cons, JSON.parse(input))
parse_json_acset_transformation(acs::ACSet, input::AbstractDict) =
parse_json_acset_transformation(constructor(acs), input)

function parse_json_acset_transformation(cons, input::AbstractDict)
domain = parse_json_acset(cons(), input["dom"])
codomain = parse_json_acset(cons(), input["codom"])
hom_keys = filter(keys(input["components"])) do k
Symbol(k) ∉ (attrtypes ∘ acset_schema)(domain)
end
# TODO: Support VarFunctions that are not empty.
ACSetTransformation(
NamedTuple{Tuple(Symbol.(hom_keys))}(
Iterators.map(hom_keys) do k
parse_json_fin_function(input["components"][k])
end),
domain,
codomain)
end

""" Deserialize an ACSetTransformation object from a JSON file.

Inverse to [`write_json_acset_transformation`](@ref).
"""
function read_json_acset_transformation(ty, fname::AbstractString)
parse_json_acset_transformation(ty, JSON.parsefile(fname))
end

end # module

4 changes: 4 additions & 0 deletions test/categorical_algebra/CategoricalAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,9 @@ end
include("Slices.jl")
end

@testset "JSONCSetTransformations" begin
include("JSONCSetTransformations.jl")
end


end
33 changes: 33 additions & 0 deletions test/categorical_algebra/JSONCSetTransformations.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# FinFunction serialization
###########################
function roundtrip_json_fin_function(f::T) where T <: FinFunction
mktempdir() do dir
path = joinpath(dir, "fin_function.json")
write_json_fin_function(f, path)
read_json_fin_function(path)
end
end

f = FinFunction([2,3], 2, 4)
g = FinFunction([2], 1, 3)

for ϕ in [f,g]
@test roundtrip_json_fin_function(ϕ) == ϕ
end

# ACSetTransformation serialization
###################################

function roundtrip_json_acset_transformation(x, t)
mktempdir() do dir
path = joinpath(dir, "acset_transformation.json")
write_json_acset_transformation(x, path)
read_json_acset_transformation(t, path)
end
end

g = path_graph(WeightedGraph{Float64}, 2, E=(weight=2,))
h = path_graph(WeightedGraph{Float64}, 4, E=(weight=[1,2,3],))
α = ACSetTransformation((V=[2,3], E=[2]), g, h)
@test roundtrip_json_acset_transformation(α, WeightedGraph{Float64}) == α

Loading