Skip to content

Commit

Permalink
Merge pull request #79 from AlgebraicJulia/acset-json3-serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfairbanks authored Nov 13, 2023
2 parents a7b19ff + de26af7 commit 0f4fd2c
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 37 deletions.
9 changes: 1 addition & 8 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
name = "ACSets"
uuid = "227ef7b5-1206-438b-ac65-934d6da304b8"
license = "MIT"
authors = [
"Owen Lynch <[email protected]>",
"Kris Brown <[email protected]>",
"Evan Patterson <[email protected]>",
"AlgebraicJulia Team",
]
authors = ["Owen Lynch <[email protected]>", "Kris Brown <[email protected]>", "Evan Patterson <[email protected]>", "AlgebraicJulia Team"]
version = "0.2.10"

[deps]
AlgebraicInterfaces = "23cfdc9f-0504-424a-be1f-4892b28e2f0c"
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
CompTime = "0fb5dd42-039a-4ca4-a1d7-89a96eae6d39"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Expand All @@ -41,7 +35,6 @@ AlgebraicInterfaces = "0.1"
Base64 = "1.9"
CompTime = "0.1"
DataStructures = "0.18"
JSON = "0.21"
JSON3 = "1.13.2"
MLStyle = "0.4"
OrderedCollections = "1.6.2"
Expand Down
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[deps]
ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
18 changes: 9 additions & 9 deletions docs/literate/json_serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This functionality should allow you to interoperate with database representations
# in other languages by serializing both the data and the type into a network interoperability layer.

import JSON, JSONSchema
import JSON3, JSONSchema

using ACSets

Expand All @@ -30,7 +30,7 @@ end
# Attrs are the names of columns that point into the AttrTypes.

json_schema = JSONSchema.Schema(acset_schema_json_schema())
JSON.print(json_schema, 2)
JSON3.print(json_schema, 2)

# ## Example 1: Discrete Dynamical Systems
#
Expand All @@ -40,15 +40,15 @@ JSON.print(json_schema, 2)

SchDDS = BasicSchema([:X], [(:next,:X,:X)])

JSON.print(generate_json_acset_schema(SchDDS), 2)
JSON3.print(generate_json_acset_schema(SchDDS), 2)

# LabeledDDS are a variation on DDS where the states can have symbolic names. In Catlab, every element of an object has to be identified by its integer row number.
# This comes out of a tradition in database design where every table has a natural number primary key. In mathematics, we often want to think of the state space not as a set of integers, but as an arbitrary set. In Catlab, we call that set the Labels and use a `label` attribute to implement the mapping of state numbers to state labels. This way the underlying database implementation can still be designed aroung natural number primary keys, but the user can use symbolic labels. Note also that this shows the schema inheritance. We state that a `SchLabeledDDS` inherits from `SchDDS` by adding a `label` attribute of type `Label`.

SchLabeledDDS = BasicSchema([:X], [(:next,:X,:X)],
[:Label], [(:label,:X,:Label)])

JSON.print(generate_json_acset_schema(SchLabeledDDS), 2)
JSON3.print(generate_json_acset_schema(SchLabeledDDS), 2)

# ## Example 2: Labeled DDS
#
Expand All @@ -66,7 +66,7 @@ JSON.print(generate_json_acset_schema(SchLabeledDDS), 2)

ldds = LabeledDDS{Int}()
add_parts!(ldds, :X, 4, next=[2,3,4,1], label=[100, 101, 102, 103])
JSON.print(generate_json_acset(ldds),2)
JSON3.print(generate_json_acset(ldds),2)

# ## Example 3: Graphs
#
Expand All @@ -82,7 +82,7 @@ JSON.print(generate_json_acset(ldds),2)

SchGraph = BasicSchema([:V,:E], [(:src,:E,:V),(:tgt,:E,:V)])

JSON.print(generate_json_acset_schema(SchGraph), 2)
JSON3.print(generate_json_acset_schema(SchGraph), 2)

# An example graph with 4 vertices and 2 edges.

Expand All @@ -94,7 +94,7 @@ add_parts!(g, :E, 2, src=[1,2], tgt=[2,3])

# Note that the vertices are listed out in a somewhat silly way. They are given as a table with no columns, so they show up in the JSON as a bunch of empty objects. This is for consistency with our next example.

JSON.print(generate_json_acset(g), 2)
JSON3.print(generate_json_acset(g), 2)

# ## Example 4: Vertex and Edge Labeled Graph Graph Schema
#
Expand All @@ -110,7 +110,7 @@ JSON.print(generate_json_acset(g), 2)
SchVELabeledGraph = BasicSchema([:V,:E], [(:src,:E,:V),(:tgt,:E,:V)],
[:Label], [(:vlabel,:V,:Label),(:elabel,:E,:Label)])

JSON.print(generate_json_acset_schema(SchVELabeledGraph), 2)
JSON3.print(generate_json_acset_schema(SchVELabeledGraph), 2)

# An example labeled graph using symbols for the vertex and edge names. Note that you can use unicode symbols in Julia.

Expand All @@ -122,4 +122,4 @@ add_parts!(lg, :E, 2, src=[1,2], tgt=[2,3], elabel=[:e₁, :e₂])

# This Graph is represented by the following JSON. Now you can see that the vertices have their `vlabels`

JSON.print(generate_json_acset(lg), 2)
JSON3.print(generate_json_acset(lg), 2)
34 changes: 20 additions & 14 deletions src/serialization/JSONACSets.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
""" JSON serialization of acsets and acset schemas.
"""
module JSONACSets

import JSON3

export generate_json_acset, parse_json_acset, read_json_acset, write_json_acset,
generate_json_acset_schema, parse_json_acset_schema,
read_json_acset_schema, write_json_acset_schema, acset_schema_json_schema
read_json_acset_schema, write_json_acset_schema, acset_schema_json_schema, write

import JSON
using DataStructures: OrderedDict
import Pkg
import Tables
Expand Down Expand Up @@ -46,7 +48,7 @@ Inverse to [`generate_json_acset`](@ref).
parse_json_acset(cons, input::AbstractDict) =
parse_json_acset!(cons(), input)
parse_json_acset(cons, input::AbstractString) =
parse_json_acset(cons, JSON.parse(input))
parse_json_acset(cons, JSON3.read(input))
parse_json_acset(acs::ACSet, input::AbstractDict) =
parse_json_acset(constructor(acs), input)

Expand Down Expand Up @@ -81,18 +83,20 @@ end
Inverse to [`write_json_acset`](@ref).
"""
function read_json_acset(ty, fname::AbstractString)
parse_json_acset(ty, JSON.parsefile(fname))
parse_json_acset(ty, JSON3.read(fname))
end

""" Serialize an ACSet object to a JSON file.
Inverse to [`read_json_acset`](@ref).
"""
function write_json_acset(x::ACSet, fname::AbstractString)
open(fname, "w") do f
write(f, JSON.json(generate_json_acset(x)))
end
end
write_json_acset(x::ACSet, fname::AbstractString) = JSON3.write(fname, x)

""" Dispatch for ACSet
Dispatches write to accept ACSets
"""
JSON3.write(io::IO, acs::ACSet; kwargs...) = JSON3.write(io, generate_json_acset(acs); kwargs...)

# Schema serialization
######################
Expand Down Expand Up @@ -150,7 +154,7 @@ function parse_json_acset_schema(::Type{BasicSchema}, data::AbstractDict)
end

function parse_json_acset_schema(T, input::AbstractString)
parse_json_acset_schema(T, JSON.parse(input))
parse_json_acset_schema(T, JSON3.read(input))
end

""" Deserialize ACSet schema from JSON file.
Expand All @@ -159,7 +163,7 @@ Similar to [`parse_json_acset_schema`](@ref) except reads from a file.
Inverse to [`write_json_acset_schema`](@ref).
"""
function read_json_acset_schema(T, fname::AbstractString)
parse_json_acset_schema(T, JSON.parsefile(fname))
parse_json_acset_schema(T, JSON3.read(fname))
end

""" Serialize ACSet schema to JSON file.
Expand All @@ -169,7 +173,7 @@ Inverse to [`read_json_acset_schema`](@ref).
"""
function write_json_acset_schema(schema, fname::AbstractString)
open(fname, "w") do f
write(f, JSON.json(generate_json_acset_schema(schema)))
write(f, JSON3.write(generate_json_acset_schema(schema)))
end
end

Expand All @@ -179,8 +183,10 @@ The result is a JSON-able object (dictionary) from which a `JSONSchema.Schema`
can be constructed, using the package JSONSchema.jl.
"""
function acset_schema_json_schema(; kw...)
JSON.parsefile(joinpath(@__DIR__, "data", "acset.schema.json");
dicttype=OrderedDict{String,Any}, kw...)
JSON3.read(joinpath(@__DIR__, "data", "acset.schema.json"),
OrderedDict{String,Any}, kw...)
end

end


8 changes: 4 additions & 4 deletions test/ADTs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ end
end) # can't test this without CombinatorialSpaces.jl
end

using JSON
using JSON3
@testset "to_dict" begin
gspec = ACSetSpec(
:(LabeledGraph{Symbol}),
Expand All @@ -92,9 +92,9 @@ using JSON
)

@test to_dict(gspec) isa AbstractDict
@test JSON.json(to_dict(gspec)) isa String
@test JSON.Parser.parse(JSON.json(to_dict(gspec))) isa AbstractDict
@test JSON.Parser.parse(JSON.json(to_dict(gspec))) == symb2string(to_dict(gspec))
@test JSON3.write(to_dict(gspec)) isa String
@test JSON3.read(JSON3.write(to_dict(gspec))) isa AbstractDict
@test JSON3.read(JSON3.write(to_dict(gspec)), Dict{String, Any}) == symb2string(to_dict(gspec))
end

@testset "Labeled Vertices" begin
Expand Down
1 change: 0 additions & 1 deletion test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[deps]
ACSets = "227ef7b5-1206-438b-ac65-934d6da304b8"
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
Expand Down

0 comments on commit 0f4fd2c

Please sign in to comment.