diff --git a/.buildkite/jobscript.sh b/.buildkite/jobscript.sh new file mode 100755 index 0000000..d27f4ec --- /dev/null +++ b/.buildkite/jobscript.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +pwd; hostname; date + +module load julia + +echo "Running Tests..." +julia --project -e 'using Pkg; Pkg.status(); Pkg.test()' + +echo "Building Documentation..." +julia -t 16 --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.status(); Pkg.instantiate(); include("docs/make.jl")' diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000..4db484f --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,20 @@ +env: + JULIA_VERSION: "1.10.2" + +steps: + + - label: ":hammer: Build Project" + command: + - "module load julia" + - "julia --project=docs --color=yes -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate(); Pkg.precompile()'" + + - wait + + - label: ":scroll: Build docs and run tests" + command: + - "srun --cpus-per-task=16 --mem=8G --time=1:00:00 --output=.buildkite/build_%j.log --unbuffered .buildkite/jobscript.sh" + env: + JULIA_PROJECT: "docs/" + + - wait + diff --git a/Project.toml b/Project.toml index 4fd07ba..b90934d 100644 --- a/Project.toml +++ b/Project.toml @@ -32,7 +32,7 @@ NautyACSetsExt = "nauty_jll" XLSXACSetsExt = "XLSX" [compat] -AlgebraicInterfaces = "0.1" +AlgebraicInterfaces = "0.1.3" Base64 = "1.9" CompTime = "0.1" DataStructures = "0.18" diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index fcd40a1..340a7fb 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -401,7 +401,7 @@ function ACSetTableSchema(s::Schema{Symbol}, ob::Symbol) attrs = filter(Schemas.attrs(s)) do (f,d,c) d == ob end - BasicSchema{Symbol}([ob], [], attrtypes(s), attrs) + BasicSchema{Symbol}([ob], [], attrtypes(s), attrs, []) end function ACSetTableDataType(::Type{<:StructACSet{S,Ts}}, ob::Symbol) where {S,Ts} diff --git a/src/Schemas.jl b/src/Schemas.jl index d5ade8c..6fbc15f 100644 --- a/src/Schemas.jl +++ b/src/Schemas.jl @@ -3,10 +3,10 @@ module Schemas export Schema, TypeLevelSchema, BasicSchema, TypeLevelBasicSchema, typelevel, objects, attrtypes, attrtype_instantiation, homs, attrs, arrows, dom, codom, ob, hom, attrtype, attr, dom_nums, codom_nums, adom_nums, acodom_nums, types, - TypedSchema + TypedSchema, equations using StructEquality -import AlgebraicInterfaces: dom, codom, ob, hom, attr, attrtype +import AlgebraicInterfaces: dom, codom, ob, hom, attr, attrtype, equations # Schemas ######### @@ -112,44 +112,55 @@ function codom end # Basic Schemas ############### -abstract type TypeLevelBasicSchema{Name, obs, homs, attrtypes, attrs} <: TypeLevelSchema{Name} end +abstract type TypeLevelBasicSchema{Name, obs, homs, attrtypes, attrs, eqs} <: TypeLevelSchema{Name} end -const TypeLevelBasicCSetSchema{Name, obs, homs} = TypeLevelBasicSchema{Name, obs, homs, Tuple{}, Tuple{}} +const TypeLevelBasicCSetSchema{Name, obs, homs} = TypeLevelBasicSchema{Name, obs, homs, Tuple{}, Tuple{}, Tuple{}} + +# A path has sequence of hom/attr names +const Pth{Name}= Tuple{Vararg{Name}} + +# An Eq has an optional name, a dom, a codom, and pair of paths +const Eq{Name} = Tuple{Union{Nothing, Name}, Name, Name, Tuple{Pth{Name},Pth{Name}}} @struct_hash_equal struct BasicSchema{Name} <: Schema{Name} obs::Vector{Name} homs::Vector{Tuple{Name,Name,Name}} attrtypes::Vector{Name} attrs::Vector{Tuple{Name,Name,Name}} - function BasicSchema{Name}(obs, homs, attrtypes, attrs) where {Name} - new{Name}(obs, homs, attrtypes, attrs) + eqs::Vector{Eq{Name}} + function BasicSchema{Name}(obs, homs, attrtypes, attrs, eqs) where {Name} + new{Name}(obs, homs, attrtypes, attrs, eqs) end - function BasicSchema(obs::Vector{Name}, homs, attrtypes, attrs) where {Name} - new{Name}(obs, homs, attrtypes, attrs) + function BasicSchema(obs::Vector{Name}, homs, attrtypes, attrs, eqs=nothing) where {Name} + eqs = isnothing(eqs) ? Eq{Name}[] : eqs + new{Name}(obs, homs, attrtypes, attrs, eqs) end - function BasicSchema(obs::Vector{Name}, homs) where {Name} - new{Name}(obs, homs, Name[], Tuple{Name,Name,Name}[]) + function BasicSchema(obs::Vector{Name}, homs, eqs=nothing) where {Name} + eqs = isnothing(eqs) ? Eq{Name}[] : eqs + new{Name}(obs, homs, Name[], Tuple{Name,Name,Name}[], eqs) end function BasicSchema{Name}() where {Name} new( Vector{Name}(), Vector{Tuple{Name,Name,Name}}(), Vector{Name}(), - Vector{Tuple{Name,Name,Name}}() + Vector{Tuple{Name,Name,Name}}(), + Vector{Eq{Name}}() ) end end function Base.copy(s::BasicSchema{Name}) where {Name} - BasicSchema{Name}(copy(s.obs), copy(s.homs), copy(s.attrtypes), copy(s.attrs)) + BasicSchema{Name}(copy(s.obs), copy(s.homs), copy(s.attrtypes), copy(s.attrs), copy(s.eqs)) end -function Schema(::Type{TypeLevelBasicSchema{Name, obs, homs, attrtypes, attrs}}) where {Name, obs, homs, attrtypes, attrs} +function Schema(::Type{TypeLevelBasicSchema{Name, obs, homs, attrtypes, attrs, eqs}}) where {Name, obs, homs, attrtypes, attrs, eqs} BasicSchema{Name}( [obs.parameters...], [homs.parameters...], [attrtypes.parameters...], - [attrs.parameters...] + [attrs.parameters...], + [eqs.parameters...] ) end @@ -165,6 +176,9 @@ attrtypes(S::Type{<:TypeLevelBasicSchema}) = Tuple(S.parameters[4].parameters) types(S::Union{Schema,Type{<:TypeLevelSchema}}) = [objects(S)..., attrtypes(S)...] +equations(S::BasicSchema) = S.eqs +equations(S::Type{<:TypeLevelBasicSchema}) = Tuple(S.parameters[6].parameters) + attrtype_instantiation(S::Type{<:TypeLevelBasicSchema}, Ts, a::Symbol) = Ts.parameters[findfirst(attrtypes(S) .== a)] @@ -247,7 +261,8 @@ function typelevel(s::BasicSchema{Name}) where {Name} Tuple{s.obs...}, Tuple{s.homs...}, Tuple{s.attrtypes...}, - Tuple{s.attrs...} + Tuple{s.attrs...}, + Tuple{s.eqs...} } end diff --git a/src/serialization/JSONACSets.jl b/src/serialization/JSONACSets.jl index 5d8abe0..df98318 100644 --- a/src/serialization/JSONACSets.jl +++ b/src/serialization/JSONACSets.jl @@ -133,6 +133,12 @@ function generate_json_acset_schema(schema::Schema) "Attr" => map(attrs(schema)) do (f, x, y) Dict("name" => string(f), "dom" => string(x), "codom" => string(y)) end, + "equations" => map(equations(schema)) do (n, x, y, eqs) + Dict("dom" => string(x), "codom" => string(y), + "name" => isnothing(n) ? n : string(n), + "paths" => [string.(eq) for eq in collect.(eqs)], ) + end, + ) end @@ -152,7 +158,13 @@ function parse_json_acset_schema(::Type{BasicSchema}, data::AbstractDict) attrs = map(data["Attr"]) do d map(Symbol, (d["name"], d["dom"], d["codom"])) end - BasicSchema(obs, homs, attrtypes, attrs) + eqs = map(data[:equations]) do d + name = isnothing(d["name"]) ? nothing : Symbol(d["name"]) + (name, Symbol(d["dom"]), Symbol(d["codom"]), tuple(map(d["paths"]) do p + tuple(Symbol.(p)...) + end...)) + end + BasicSchema(obs, homs, attrtypes, attrs, eqs) end function parse_json_acset_schema(T, input::AbstractString) diff --git a/test/Schemas.jl b/test/Schemas.jl index ca9e076..de3807c 100644 --- a/test/Schemas.jl +++ b/test/Schemas.jl @@ -3,7 +3,10 @@ module TestSchemas using Test using ACSets.Schemas -bsch = BasicSchema([:E,:V], [(:src,:E,:V),(:tgt,:E,:V)],[:Weight],[(:weight,:E,:Weight)]) +@test BasicSchema{Symbol}() isa BasicSchema + +bsch = BasicSchema([:E,:V], [(:src,:E,:V),(:tgt,:E,:V)],[:Weight], + [(:weight,:E,:Weight)], [(nothing, :E,:V,((:src,),(:tgt,)))]) tsch = typelevel(bsch) for sch in [bsch, tsch] @test collect(ob(sch)) == collect(objects(sch)) == [:E,:V] @@ -19,6 +22,7 @@ for sch in [bsch, tsch] @test codom_nums(sch) == (2,2) @test adom_nums(sch) == (1,) @test acodom_nums(sch) == (1,) + @test collect(equations(sch)) == [(nothing, :E,:V,((:src,),(:tgt,)),)] end @test attrtype_instantiation(tsch, Tuple{Int}, :Weight) == Int diff --git a/test/serialization/JSONACSets.jl b/test/serialization/JSONACSets.jl index 0e66200..57991b1 100644 --- a/test/serialization/JSONACSets.jl +++ b/test/serialization/JSONACSets.jl @@ -42,10 +42,11 @@ add_parts!(g, :V, 3) add_parts!(g, :E, 2, src=[1,2], tgt=[2,3], weight=[0.5,1.5]) @test roundtrip_json_acset(g) == g -SchLabeledDDS = BasicSchema([:X], [(:Φ,:X,:X)], [:Label], [(:label,:X,:Label)]) -@acset_type LabeledDDS(SchLabeledDDS, index=[:Φ]) +SchLabeledDDS4 = BasicSchema([:X], [(:Φ,:X,:X)], [:Label], [(:label,:X,:Label)], + [(:cycle4,:X,:X,((),(:Φ,:Φ,:Φ,:Φ)))]) +@acset_type LabeledDDS4(SchLabeledDDS4, index=[:Φ]) -ldds = LabeledDDS{Symbol}() +ldds = LabeledDDS4{Symbol}() add_parts!(ldds, :Label, 2) add_parts!(ldds, :X, 4, Φ=[2,3,4,1], label=[AttrVar(1), :a, :b, AttrVar(2)]) @test roundtrip_json_acset(ldds) == ldds @@ -67,7 +68,7 @@ end json_schema = JSONSchema.Schema(acset_schema_json_schema()) -for schema in [SchGraph, SchWeightedGraph, SchLabeledDDS] +for schema in [SchGraph, SchWeightedGraph, SchLabeledDDS4] schema_dict = generate_json_acset_schema(schema) @test isnothing(JSONSchema.validate(json_schema, schema_dict)) @test roundtrip_json_acset_schema(schema) == schema