From f1c5dee3d9905b4a4b2c8650ff12bd6e2f90997b Mon Sep 17 00:00:00 2001 From: Kris Brown Date: Thu, 28 Sep 2023 15:08:03 -0700 Subject: [PATCH 1/9] clear parts before assigning in case of injective cache --- src/ACSetInterface.jl | 4 ++++ src/Columns.jl | 4 +++- src/PreimageCaches.jl | 11 +++++++++++ test/ACSets.jl | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ACSetInterface.jl b/src/ACSetInterface.jl index e78fda1..41c2c5b 100644 --- a/src/ACSetInterface.jl +++ b/src/ACSetInterface.jl @@ -12,6 +12,7 @@ using Tables using PrettyTables: pretty_table using ..ColumnImplementations: AttrVar +using ..PreimageCaches: is_injective using ..Schemas: types, attrs, attrtypes @@ -250,6 +251,9 @@ function set_subpart! end # Inlined for the same reason as `subpart`. @inline function set_subpart!(acs::ACSet , parts::Union{AbstractVector{Int}, AbstractSet{Int}}, name, vals) + if is_injective(acs.subparts[name]) + clear_subpart!(acs, parts, name) + end broadcast(parts, vals) do part, val set_subpart!(acs, part, name, val) end diff --git a/src/Columns.jl b/src/Columns.jl index fd72598..bb0e1ea 100644 --- a/src/Columns.jl +++ b/src/Columns.jl @@ -10,7 +10,7 @@ using Reexport @reexport using ..PreimageCaches import ..Mappings: view_with_default -import ..PreimageCaches: preimage, preimage_multi +import ..PreimageCaches: preimage, preimage_multi, is_injective # Columns ######### @@ -94,4 +94,6 @@ view_with_default(c::Column, xs, def) = ColumnView(c, xs, def) Base.size(c::ColumnView) = size(c.indices) +is_injective(c::Column) = is_injective(c.pc) + end diff --git a/src/PreimageCaches.jl b/src/PreimageCaches.jl index 205fe8a..7919084 100644 --- a/src/PreimageCaches.jl +++ b/src/PreimageCaches.jl @@ -35,6 +35,7 @@ performance implications. - [`preimage`](@ref) - [`assign!`](@ref) - [`unassign!`](@ref) +- [`is_injective`](@ref) (defaults to false if not implemented) """ abstract type PreimageCache{S,T} end @@ -94,6 +95,14 @@ Remove `x` from the preimage of `y`. """ function unassign! end +""" +Whether or not the cache imposes an injectivity constraint. (default: false) +""" +is_injective(::PreimageCache)::Bool = false + +# Caches +######## + """ The trivial preimage mapping. It just computes preimages on the fly, and the operations for updating it are noops @@ -203,4 +212,6 @@ function unassign!(pc::InjectiveCache{S,T}, y::T, x::S) where {S,T} delete!(pc.inverse, y) end +is_injective(::InjectiveCache)::Bool = true + end diff --git a/test/ACSets.jl b/test/ACSets.jl index 1482e9a..de885dd 100644 --- a/test/ACSets.jl +++ b/test/ACSets.jl @@ -425,6 +425,8 @@ for lset_maker in lset_makers @test isempty(incident(lset, :foo, :label)) @test_throws Exception set_subpart!(lset, 1, :label, :bar) + set_subpart!(lset, :, :label, [:bar, :foo]) + @test subpart(lset, :, :label) == [:bar, :foo] end SchDecGraph = BasicSchema([:E,:V], [(:src,:E,:V),(:tgt,:E,:V)], From 96bc8a30fd27958df30f5670b6c29111f172c292 Mon Sep 17 00:00:00 2001 From: slwu89 <10673535+slwu89@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:04:03 -0700 Subject: [PATCH 2/9] notes on the problem --- Project.toml | 1 + src/DenseACSets.jl | 43 ++++++++++++++++++++++++-- test/runtests.jl | 36 +++++++++++----------- tmp.jl | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 21 deletions(-) create mode 100644 tmp.jl diff --git a/Project.toml b/Project.toml index 47a1e83..1023b68 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.2.5" [deps] CompTime = "0fb5dd42-039a-4ca4-a1d7-89a96eae6d39" +Debugger = "31a5f54b-26ea-5ae9-a837-f05ce5417438" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index cdeef36..d5307f9 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -527,6 +527,15 @@ end @inline ACSetInterface.set_subpart!(acs::StructACSet{S,Ts}, part::Int, f::Symbol, subpart) where {S,Ts} = _set_subpart!(acs, Val{S}, Val{Ts}, part, Val{f}, subpart) +# using ..PreimageCaches: is_injective + +# @inline function ACSetInterface.set_subpart!(acs::StructACSet{S,Ts}, part::Int, f::Symbol, subpart) where {S,Ts} +# if is_injective(acs.subparts[f]) +# clear_subpart!(acs, part, f) +# end +# _set_subpart!(acs, Val{S}, Val{Ts}, part, Val{f}, subpart) +# end + ACSetInterface.set_subpart!(acs::DynamicACSet, part::Int, f::Symbol, subpart) = runtime(_set_subpart!, acs, acs.schema, Tuple{[acs.type_assignment[t] for t in acs.schema.attrtypes]...}, @@ -549,6 +558,8 @@ end ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = runtime(_rem_part!, acs, acs.schema, type, part, acs.parts[type]) +using Debugger + @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::DenseParts) @ct s = Schema(S) @ct in_homs = homs(s; to=ob, just_names=true) @@ -559,6 +570,7 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = last_part = acs.parts[@ct ob].val @ct_ctrl for hom in in_homs + println("currently working on in hom $(@ct hom) for ob $(@ct ob)") incoming_to_part = copy(incident(acs, part, @ct hom)) clear_subpart!(acs, incoming_to_part, @ct hom) @@ -575,13 +587,38 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = end @ct_ctrl for f in [out_homs; out_attrs] + # original + # if haskey(acs.subparts[@ct f], last_part) + # set_subpart!(acs, part, (@ct f), subpart(acs, last_part, @ct f)) + # end + # clear_subpart!(acs, last_part, @ct f) + # remixed + Debugger.@bp if haskey(acs.subparts[@ct f], last_part) - set_subpart!(acs, part, (@ct f), subpart(acs, last_part, @ct f)) - end - clear_subpart!(acs, last_part, @ct f) + + println("currently working on out hom $(@ct f) for ob $(@ct ob)") + last_part_f = subpart(acs, last_part, @ct f) + println("last_part_f is: $(last_part_f)") + + clear_subpart!(acs, last_part, @ct f) + println("after clear_subpart! the subpart looks like:") + println("$(pretty_tables(acs))") + + set_subpart!(acs, part, (@ct f), last_part_f) + println("after set_subpart! the subpart looks like:") + println("$(pretty_tables(acs))") + + else + clear_subpart!(acs, last_part, @ct f) + end end acs.parts[@ct ob].val -= 1 + println("acs now looks like:") + println("$(pretty_tables(acs))") + println("we have this many parts left:") + println("$(acs.parts)") + println("~~~~~~~~~~ OKAY BYEE THATS THE END OF THIS ITERATION!!!!!!! ~~~~~~~~~~ \n\n") end @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::MarkAsDeleted) diff --git a/test/runtests.jl b/test/runtests.jl index 8642277..33e271e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,29 +1,29 @@ using Test -@testset "Utilities" begin - include("IndexUtils.jl") -end +# @testset "Utilities" begin +# include("IndexUtils.jl") +# end -@testset "Mappings" begin - include("Mappings.jl") -end +# @testset "Mappings" begin +# include("Mappings.jl") +# end -@testset "Columns" begin - include("Columns.jl") -end +# @testset "Columns" begin +# include("Columns.jl") +# end -@testset "Schemas" begin - include("Schemas.jl") -end +# @testset "Schemas" begin +# include("Schemas.jl") +# end @testset "ACSets" begin include("ACSets.jl") end -@testset "JSON" begin - include("JSONACSets.jl") -end +# @testset "JSON" begin +# include("JSONACSets.jl") +# end -@testset "ADTs" begin - include("ADTs.jl") -end \ No newline at end of file +# @testset "ADTs" begin +# include("ADTs.jl") +# end \ No newline at end of file diff --git a/tmp.jl b/tmp.jl new file mode 100644 index 0000000..eb002e7 --- /dev/null +++ b/tmp.jl @@ -0,0 +1,75 @@ +using Revise, ACSets +MySch = BasicSchema([:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)],[],[]) + +@acset_type MyData(MySch, index=[:src,:tgt], unique_index=[:thing]) + +mydata = @acset MyData begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] +end + +# by hand -------------------------------------------------- +delparts = Dict(:Node=>1) +acs = mydata +X = deepcopy(acs) +dels = DenseACSets.delete_subobj(X, delparts) + +# go into delete_subobj! +for o in ob(acset_schema(X)) + # o = :Thing + + ps = collect(parts(X,o)) + for r in dels[o] + # r = 1 + idx = findfirst(==(r), ps) + idx2 = pop!(ps) + if idx <= length(ps) + ps[idx] = idx2 # map from new to old + end + # rem_parts!(X, o, dels[o]) + rem_part!(X, o, dels[o][1]) + end + +end + +# "going into" rem_part! +s = acset_schema(X) +part = dels[o][1] +in_homs = homs(s; to=o, just_names=true) +in_attrs = attrs(s; to=o, just_names=true) +out_homs = homs(s; from=o, just_names=true) +out_attrs = attrs(s; from=o, just_names=true) + +last_part = X.parts[o].val + +f = only(out_homs) + +if haskey(X.subparts[f], last_part) + # subpart(X, last_part, f) is the last_part's value of the subpart f + # we then set part's subpart to that value + set_subpart!(X, part, f, subpart(X, last_part, f)) +end +clear_subpart!(X, last_part, f) + + + +# errors +cascading_rem_parts!(mydata, :Node, 1) + +@acset_type MyDataNoInjective(MySch, index=[:src,:tgt,:thing]) + +mydatanoinj = @acset MyDataNoInjective begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] +end + +# no error +cascading_rem_parts!(mydatanoinj, :Node, 1) \ No newline at end of file From 2f50e89f4075290470d0beb40a339f0ff86e8d21 Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 09:50:29 -0700 Subject: [PATCH 3/9] possible soln, is passing tests --- src/DenseACSets.jl | 13 ++++++++++--- tmp.jl | 30 +++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index d5307f9..dfb4ee5 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -561,6 +561,7 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = using Debugger @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::DenseParts) + println("********** OKAY HI THATS THE START OF THIS ITERATION!!!!!!! **********") @ct s = Schema(S) @ct in_homs = homs(s; to=ob, just_names=true) @ct in_attrs = attrs(s; to=ob, just_names=true) @@ -573,10 +574,13 @@ using Debugger println("currently working on in hom $(@ct hom) for ob $(@ct ob)") incoming_to_part = copy(incident(acs, part, @ct hom)) clear_subpart!(acs, incoming_to_part, @ct hom) + println("going to clear these parts: $(incoming_to_part) of the hom") incoming_to_last_part = copy(incident(acs, last_part, @ct hom)) set_subpart!(acs, incoming_to_last_part, (@ct hom), part) + println("going to set these parts: $(incoming_to_last_part) of the hom to $(part)") end + println("$(pretty_tables(acs))") @ct_ctrl for hom in in_attrs incoming_to_part = copy(incident(acs, AttrVar(part), @ct hom)) @@ -604,11 +608,14 @@ using Debugger println("after clear_subpart! the subpart looks like:") println("$(pretty_tables(acs))") - set_subpart!(acs, part, (@ct f), last_part_f) - println("after set_subpart! the subpart looks like:") - println("$(pretty_tables(acs))") + if part != last_part + set_subpart!(acs, part, (@ct f), last_part_f) + println("after set_subpart! the subpart looks like:") + println("$(pretty_tables(acs))") + end else + println("currently working on out hom $(@ct f) for ob $(@ct ob), just clearing subpart: $(last_part)") clear_subpart!(acs, last_part, @ct f) end end diff --git a/tmp.jl b/tmp.jl index eb002e7..e454522 100644 --- a/tmp.jl +++ b/tmp.jl @@ -1,6 +1,8 @@ using Revise, ACSets MySch = BasicSchema([:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)],[],[]) +# INJECTIVE HOM -------------------------------------------------- + @acset_type MyData(MySch, index=[:src,:tgt], unique_index=[:thing]) mydata = @acset MyData begin @@ -12,6 +14,9 @@ mydata = @acset MyData begin tgt=[1,2,3] end +# errors +cascading_rem_parts!(mydata, :Node, 1) + # by hand -------------------------------------------------- delparts = Dict(:Node=>1) acs = mydata @@ -55,10 +60,7 @@ if haskey(X.subparts[f], last_part) end clear_subpart!(X, last_part, f) - - -# errors -cascading_rem_parts!(mydata, :Node, 1) +# REGULAR HOM -------------------------------------------------- @acset_type MyDataNoInjective(MySch, index=[:src,:tgt,:thing]) @@ -72,4 +74,22 @@ mydatanoinj = @acset MyDataNoInjective begin end # no error -cascading_rem_parts!(mydatanoinj, :Node, 1) \ No newline at end of file +cascading_rem_parts!(mydatanoinj, :Node, 1) + + +# FAILING TESTS -------------------------------------------------- +using Test +SchDDS = BasicSchema([:X], [(:Φ,:X,:X)]) + +@abstract_acset_type AbstractDDS +@acset_type DDS(SchDDS, index=[:Φ]) <: AbstractDDS + +dds = DDS() +add_parts!(dds, :X, 3, Φ=[1,1,1]) +@test !isempty(dds) +@test_throws AssertionError add_part!(dds, :X, Φ=5) +@test nparts(dds, :X) == 3 +@test subpart(dds, :Φ) == [1,1,1] +@test_throws AssertionError add_parts!(dds, :X, 2, Φ=[3,6]) +@test nparts(dds, :X) == 3 +@test incident(dds, 3, :Φ) == [] \ No newline at end of file From 5e263e3a27e2a2388d07eed06cfaf499361bd6f1 Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 10:03:36 -0700 Subject: [PATCH 4/9] test for recursive deletion without attrs --- Project.toml | 1 - src/DenseACSets.jl | 46 +++++++++++++++------------------------- test/ACSets.jl | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/Project.toml b/Project.toml index 1023b68..47a1e83 100644 --- a/Project.toml +++ b/Project.toml @@ -6,7 +6,6 @@ version = "0.2.5" [deps] CompTime = "0fb5dd42-039a-4ca4-a1d7-89a96eae6d39" -Debugger = "31a5f54b-26ea-5ae9-a837-f05ce5417438" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index dfb4ee5..db8e9f5 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -527,15 +527,6 @@ end @inline ACSetInterface.set_subpart!(acs::StructACSet{S,Ts}, part::Int, f::Symbol, subpart) where {S,Ts} = _set_subpart!(acs, Val{S}, Val{Ts}, part, Val{f}, subpart) -# using ..PreimageCaches: is_injective - -# @inline function ACSetInterface.set_subpart!(acs::StructACSet{S,Ts}, part::Int, f::Symbol, subpart) where {S,Ts} -# if is_injective(acs.subparts[f]) -# clear_subpart!(acs, part, f) -# end -# _set_subpart!(acs, Val{S}, Val{Ts}, part, Val{f}, subpart) -# end - ACSetInterface.set_subpart!(acs::DynamicACSet, part::Int, f::Symbol, subpart) = runtime(_set_subpart!, acs, acs.schema, Tuple{[acs.type_assignment[t] for t in acs.schema.attrtypes]...}, @@ -558,10 +549,8 @@ end ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = runtime(_rem_part!, acs, acs.schema, type, part, acs.parts[type]) -using Debugger - @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::DenseParts) - println("********** OKAY HI THATS THE START OF THIS ITERATION!!!!!!! **********") + # println("********** OKAY HI THATS THE START OF THIS ITERATION!!!!!!! **********") @ct s = Schema(S) @ct in_homs = homs(s; to=ob, just_names=true) @ct in_attrs = attrs(s; to=ob, just_names=true) @@ -571,16 +560,16 @@ using Debugger last_part = acs.parts[@ct ob].val @ct_ctrl for hom in in_homs - println("currently working on in hom $(@ct hom) for ob $(@ct ob)") + # println("currently working on in hom $(@ct hom) for ob $(@ct ob)") incoming_to_part = copy(incident(acs, part, @ct hom)) clear_subpart!(acs, incoming_to_part, @ct hom) - println("going to clear these parts: $(incoming_to_part) of the hom") + # println("going to clear these parts: $(incoming_to_part) of the hom") incoming_to_last_part = copy(incident(acs, last_part, @ct hom)) set_subpart!(acs, incoming_to_last_part, (@ct hom), part) - println("going to set these parts: $(incoming_to_last_part) of the hom to $(part)") + # println("going to set these parts: $(incoming_to_last_part) of the hom to $(part)") end - println("$(pretty_tables(acs))") + # println("$(pretty_tables(acs))") @ct_ctrl for hom in in_attrs incoming_to_part = copy(incident(acs, AttrVar(part), @ct hom)) @@ -597,35 +586,34 @@ using Debugger # end # clear_subpart!(acs, last_part, @ct f) # remixed - Debugger.@bp if haskey(acs.subparts[@ct f], last_part) - println("currently working on out hom $(@ct f) for ob $(@ct ob)") + # println("currently working on out hom $(@ct f) for ob $(@ct ob)") last_part_f = subpart(acs, last_part, @ct f) - println("last_part_f is: $(last_part_f)") + # println("last_part_f is: $(last_part_f)") clear_subpart!(acs, last_part, @ct f) - println("after clear_subpart! the subpart looks like:") - println("$(pretty_tables(acs))") + # println("after clear_subpart! the subpart looks like:") + # println("$(pretty_tables(acs))") if part != last_part set_subpart!(acs, part, (@ct f), last_part_f) - println("after set_subpart! the subpart looks like:") - println("$(pretty_tables(acs))") + # println("after set_subpart! the subpart looks like:") + # println("$(pretty_tables(acs))") end else - println("currently working on out hom $(@ct f) for ob $(@ct ob), just clearing subpart: $(last_part)") + # println("currently working on out hom $(@ct f) for ob $(@ct ob), just clearing subpart: $(last_part)") clear_subpart!(acs, last_part, @ct f) end end acs.parts[@ct ob].val -= 1 - println("acs now looks like:") - println("$(pretty_tables(acs))") - println("we have this many parts left:") - println("$(acs.parts)") - println("~~~~~~~~~~ OKAY BYEE THATS THE END OF THIS ITERATION!!!!!!! ~~~~~~~~~~ \n\n") + # println("acs now looks like:") + # println("$(pretty_tables(acs))") + # println("we have this many parts left:") + # println("$(acs.parts)") + # println("~~~~~~~~~~ OKAY BYEE THATS THE END OF THIS ITERATION!!!!!!! ~~~~~~~~~~ \n\n") end @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::MarkAsDeleted) diff --git a/test/ACSets.jl b/test/ACSets.jl index de885dd..d7e5b2a 100644 --- a/test/ACSets.jl +++ b/test/ACSets.jl @@ -577,4 +577,57 @@ g′′ = sparsify(g′) @test g′[:src] == [1,2] @test g′′[:src] == [1,2] +# Recursive deletion +#------------------- + +RecSch = BasicSchema( + [:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)], + [],[] +) + +@acset_type RecDataInj(RecSch, index=[:src,:tgt], unique_index=[:thing]) +@acset_type RecDataIdx(RecSch, index=[:src,:tgt,:thing]) +@acset_type RecDataNoIdx(RecSch) + +datainj = @acset RecDataInj begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] +end + +dataidx = @acset RecDataIdx begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] +end + +datanoidx = @acset RecDataNoIdx begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] +end + +map_inj = cascading_rem_parts!(datainj, :Node, 1) +map_idx = cascading_rem_parts!(dataidx, :Node, 1) +map_noidx = cascading_rem_parts!(datanoidx, :Node, 1) + +@test map_inj == map_idx +@test map_idx == map_noidx + +@test nparts(datainj,:Thing) == 2 +@test nparts(datainj,:Node) == 2 +@test nparts(datainj,:Edge) == 1 +@test incident(datainj, 3, :thing) == [] +@test incident(datainj, 3, :src) == [] +@test incident(datainj, 3, :tgt) == [] + end From 5ec4b7972da258d930f06e445650f59f1fea5015 Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 10:06:32 -0700 Subject: [PATCH 5/9] uncomment all testsets --- test/ACSets.jl | 4 ++-- test/runtests.jl | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/ACSets.jl b/test/ACSets.jl index d7e5b2a..2577bc0 100644 --- a/test/ACSets.jl +++ b/test/ACSets.jl @@ -577,8 +577,8 @@ g′′ = sparsify(g′) @test g′[:src] == [1,2] @test g′′[:src] == [1,2] -# Recursive deletion -#------------------- +# Recursive deletion with indexing +#--------------------------------- RecSch = BasicSchema( [:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)], diff --git a/test/runtests.jl b/test/runtests.jl index 33e271e..8642277 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,29 +1,29 @@ using Test -# @testset "Utilities" begin -# include("IndexUtils.jl") -# end +@testset "Utilities" begin + include("IndexUtils.jl") +end -# @testset "Mappings" begin -# include("Mappings.jl") -# end +@testset "Mappings" begin + include("Mappings.jl") +end -# @testset "Columns" begin -# include("Columns.jl") -# end +@testset "Columns" begin + include("Columns.jl") +end -# @testset "Schemas" begin -# include("Schemas.jl") -# end +@testset "Schemas" begin + include("Schemas.jl") +end @testset "ACSets" begin include("ACSets.jl") end -# @testset "JSON" begin -# include("JSONACSets.jl") -# end +@testset "JSON" begin + include("JSONACSets.jl") +end -# @testset "ADTs" begin -# include("ADTs.jl") -# end \ No newline at end of file +@testset "ADTs" begin + include("ADTs.jl") +end \ No newline at end of file From 06603b593c0a22c8281c29fe84235f91483d111a Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 10:09:31 -0700 Subject: [PATCH 6/9] rm debug comments --- src/DenseACSets.jl | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index db8e9f5..817ac83 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -550,7 +550,6 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = runtime(_rem_part!, acs, acs.schema, type, part, acs.parts[type]) @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::DenseParts) - # println("********** OKAY HI THATS THE START OF THIS ITERATION!!!!!!! **********") @ct s = Schema(S) @ct in_homs = homs(s; to=ob, just_names=true) @ct in_attrs = attrs(s; to=ob, just_names=true) @@ -560,16 +559,12 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = last_part = acs.parts[@ct ob].val @ct_ctrl for hom in in_homs - # println("currently working on in hom $(@ct hom) for ob $(@ct ob)") incoming_to_part = copy(incident(acs, part, @ct hom)) clear_subpart!(acs, incoming_to_part, @ct hom) - # println("going to clear these parts: $(incoming_to_part) of the hom") incoming_to_last_part = copy(incident(acs, last_part, @ct hom)) set_subpart!(acs, incoming_to_last_part, (@ct hom), part) - # println("going to set these parts: $(incoming_to_last_part) of the hom to $(part)") end - # println("$(pretty_tables(acs))") @ct_ctrl for hom in in_attrs incoming_to_part = copy(incident(acs, AttrVar(part), @ct hom)) @@ -580,40 +575,17 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = end @ct_ctrl for f in [out_homs; out_attrs] - # original - # if haskey(acs.subparts[@ct f], last_part) - # set_subpart!(acs, part, (@ct f), subpart(acs, last_part, @ct f)) - # end - # clear_subpart!(acs, last_part, @ct f) - # remixed if haskey(acs.subparts[@ct f], last_part) - - # println("currently working on out hom $(@ct f) for ob $(@ct ob)") last_part_f = subpart(acs, last_part, @ct f) - # println("last_part_f is: $(last_part_f)") - clear_subpart!(acs, last_part, @ct f) - # println("after clear_subpart! the subpart looks like:") - # println("$(pretty_tables(acs))") - if part != last_part set_subpart!(acs, part, (@ct f), last_part_f) - # println("after set_subpart! the subpart looks like:") - # println("$(pretty_tables(acs))") end - else - # println("currently working on out hom $(@ct f) for ob $(@ct ob), just clearing subpart: $(last_part)") clear_subpart!(acs, last_part, @ct f) end end - acs.parts[@ct ob].val -= 1 - # println("acs now looks like:") - # println("$(pretty_tables(acs))") - # println("we have this many parts left:") - # println("$(acs.parts)") - # println("~~~~~~~~~~ OKAY BYEE THATS THE END OF THIS ITERATION!!!!!!! ~~~~~~~~~~ \n\n") end @ct_enable function _rem_part!(acs::SimpleACSet, @ct(S), @ct(ob), part, ::MarkAsDeleted) From 80a4d68530635f2386b4d24df277c688504eae2a Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 10:35:53 -0700 Subject: [PATCH 7/9] note to clean up logic --- src/DenseACSets.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index 817ac83..06d480a 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -575,6 +575,7 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = end @ct_ctrl for f in [out_homs; out_attrs] + # clean up with rather messy logic somehow, too many branches if haskey(acs.subparts[@ct f], last_part) last_part_f = subpart(acs, last_part, @ct f) clear_subpart!(acs, last_part, @ct f) From e4fbb26c347c843236857138ae7485db0b67ef1e Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 10:39:40 -0700 Subject: [PATCH 8/9] Revert "clear parts before assigning in case of injective cache" This reverts commit f1c5dee3d9905b4a4b2c8650ff12bd6e2f90997b. --- src/ACSetInterface.jl | 4 ---- src/Columns.jl | 4 +--- src/PreimageCaches.jl | 11 ----------- test/ACSets.jl | 2 -- 4 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/ACSetInterface.jl b/src/ACSetInterface.jl index 41c2c5b..e78fda1 100644 --- a/src/ACSetInterface.jl +++ b/src/ACSetInterface.jl @@ -12,7 +12,6 @@ using Tables using PrettyTables: pretty_table using ..ColumnImplementations: AttrVar -using ..PreimageCaches: is_injective using ..Schemas: types, attrs, attrtypes @@ -251,9 +250,6 @@ function set_subpart! end # Inlined for the same reason as `subpart`. @inline function set_subpart!(acs::ACSet , parts::Union{AbstractVector{Int}, AbstractSet{Int}}, name, vals) - if is_injective(acs.subparts[name]) - clear_subpart!(acs, parts, name) - end broadcast(parts, vals) do part, val set_subpart!(acs, part, name, val) end diff --git a/src/Columns.jl b/src/Columns.jl index bb0e1ea..fd72598 100644 --- a/src/Columns.jl +++ b/src/Columns.jl @@ -10,7 +10,7 @@ using Reexport @reexport using ..PreimageCaches import ..Mappings: view_with_default -import ..PreimageCaches: preimage, preimage_multi, is_injective +import ..PreimageCaches: preimage, preimage_multi # Columns ######### @@ -94,6 +94,4 @@ view_with_default(c::Column, xs, def) = ColumnView(c, xs, def) Base.size(c::ColumnView) = size(c.indices) -is_injective(c::Column) = is_injective(c.pc) - end diff --git a/src/PreimageCaches.jl b/src/PreimageCaches.jl index 7919084..205fe8a 100644 --- a/src/PreimageCaches.jl +++ b/src/PreimageCaches.jl @@ -35,7 +35,6 @@ performance implications. - [`preimage`](@ref) - [`assign!`](@ref) - [`unassign!`](@ref) -- [`is_injective`](@ref) (defaults to false if not implemented) """ abstract type PreimageCache{S,T} end @@ -95,14 +94,6 @@ Remove `x` from the preimage of `y`. """ function unassign! end -""" -Whether or not the cache imposes an injectivity constraint. (default: false) -""" -is_injective(::PreimageCache)::Bool = false - -# Caches -######## - """ The trivial preimage mapping. It just computes preimages on the fly, and the operations for updating it are noops @@ -212,6 +203,4 @@ function unassign!(pc::InjectiveCache{S,T}, y::T, x::S) where {S,T} delete!(pc.inverse, y) end -is_injective(::InjectiveCache)::Bool = true - end diff --git a/test/ACSets.jl b/test/ACSets.jl index 2577bc0..b73e88b 100644 --- a/test/ACSets.jl +++ b/test/ACSets.jl @@ -425,8 +425,6 @@ for lset_maker in lset_makers @test isempty(incident(lset, :foo, :label)) @test_throws Exception set_subpart!(lset, 1, :label, :bar) - set_subpart!(lset, :, :label, [:bar, :foo]) - @test subpart(lset, :, :label) == [:bar, :foo] end SchDecGraph = BasicSchema([:E,:V], [(:src,:E,:V),(:tgt,:E,:V)], From bac94a0854d5307a2315919dcf115e190127ae01 Mon Sep 17 00:00:00 2001 From: slwu89 Date: Sat, 30 Sep 2023 15:20:11 -0700 Subject: [PATCH 9/9] clean up code, tests, remove temp file --- src/DenseACSets.jl | 7 +--- test/ACSets.jl | 28 ++++++++++++++ tmp.jl | 95 ---------------------------------------------- 3 files changed, 30 insertions(+), 100 deletions(-) delete mode 100644 tmp.jl diff --git a/src/DenseACSets.jl b/src/DenseACSets.jl index 06d480a..5e7cc15 100644 --- a/src/DenseACSets.jl +++ b/src/DenseACSets.jl @@ -575,13 +575,10 @@ ACSetInterface.rem_part!(acs::DynamicACSet, type::Symbol, part::Int) = end @ct_ctrl for f in [out_homs; out_attrs] - # clean up with rather messy logic somehow, too many branches - if haskey(acs.subparts[@ct f], last_part) + if haskey(acs.subparts[@ct f], last_part) && part != last_part last_part_f = subpart(acs, last_part, @ct f) clear_subpart!(acs, last_part, @ct f) - if part != last_part - set_subpart!(acs, part, (@ct f), last_part_f) - end + set_subpart!(acs, part, (@ct f), last_part_f) else clear_subpart!(acs, last_part, @ct f) end diff --git a/test/ACSets.jl b/test/ACSets.jl index b73e88b..9e0d581 100644 --- a/test/ACSets.jl +++ b/test/ACSets.jl @@ -628,4 +628,32 @@ map_noidx = cascading_rem_parts!(datanoidx, :Node, 1) @test incident(datainj, 3, :src) == [] @test incident(datainj, 3, :tgt) == [] +# attributes and an injective index +RecAttrSch = BasicSchema( + [:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)], + [:Attr1,:Attr2,:Attr3],[(:attr1,:Node,:Attr1),(:attr2,:Edge,:Attr2),(:attr3,:Thing,:Attr3)] +) + +@acset_type RecAttrData(RecAttrSch, index=[:src,:tgt], unique_index=[:thing]) + +dataattr = @acset RecAttrData{String,Symbol,Float64} begin + Thing=3 + Node=3 + Edge=3 + thing=[1,2,3] + src=[1,1,2] + tgt=[1,2,3] + attr1=["1","2","3"] + attr2=[:a,:b,:c] + attr3=[10.0,11.0,12.0] end + +map_attr = cascading_rem_parts!(dataattr, :Node, 1) + +@test map_inj == map_attr + +@test all(map(x -> x ∈ subpart(dataattr,:attr1), ["2","3"])) +@test only(subpart(dataattr,:attr2)) == :c +@test all(map(x -> x ∈ subpart(dataattr,:attr3), [12.0,11.0])) + +end \ No newline at end of file diff --git a/tmp.jl b/tmp.jl deleted file mode 100644 index e454522..0000000 --- a/tmp.jl +++ /dev/null @@ -1,95 +0,0 @@ -using Revise, ACSets -MySch = BasicSchema([:Thing,:Node,:Edge], [(:src,:Edge,:Node),(:tgt,:Edge,:Node),(:thing,:Thing,:Node)],[],[]) - -# INJECTIVE HOM -------------------------------------------------- - -@acset_type MyData(MySch, index=[:src,:tgt], unique_index=[:thing]) - -mydata = @acset MyData begin - Thing=3 - Node=3 - Edge=3 - thing=[1,2,3] - src=[1,1,2] - tgt=[1,2,3] -end - -# errors -cascading_rem_parts!(mydata, :Node, 1) - -# by hand -------------------------------------------------- -delparts = Dict(:Node=>1) -acs = mydata -X = deepcopy(acs) -dels = DenseACSets.delete_subobj(X, delparts) - -# go into delete_subobj! -for o in ob(acset_schema(X)) - # o = :Thing - - ps = collect(parts(X,o)) - for r in dels[o] - # r = 1 - idx = findfirst(==(r), ps) - idx2 = pop!(ps) - if idx <= length(ps) - ps[idx] = idx2 # map from new to old - end - # rem_parts!(X, o, dels[o]) - rem_part!(X, o, dels[o][1]) - end - -end - -# "going into" rem_part! -s = acset_schema(X) -part = dels[o][1] -in_homs = homs(s; to=o, just_names=true) -in_attrs = attrs(s; to=o, just_names=true) -out_homs = homs(s; from=o, just_names=true) -out_attrs = attrs(s; from=o, just_names=true) - -last_part = X.parts[o].val - -f = only(out_homs) - -if haskey(X.subparts[f], last_part) - # subpart(X, last_part, f) is the last_part's value of the subpart f - # we then set part's subpart to that value - set_subpart!(X, part, f, subpart(X, last_part, f)) -end -clear_subpart!(X, last_part, f) - -# REGULAR HOM -------------------------------------------------- - -@acset_type MyDataNoInjective(MySch, index=[:src,:tgt,:thing]) - -mydatanoinj = @acset MyDataNoInjective begin - Thing=3 - Node=3 - Edge=3 - thing=[1,2,3] - src=[1,1,2] - tgt=[1,2,3] -end - -# no error -cascading_rem_parts!(mydatanoinj, :Node, 1) - - -# FAILING TESTS -------------------------------------------------- -using Test -SchDDS = BasicSchema([:X], [(:Φ,:X,:X)]) - -@abstract_acset_type AbstractDDS -@acset_type DDS(SchDDS, index=[:Φ]) <: AbstractDDS - -dds = DDS() -add_parts!(dds, :X, 3, Φ=[1,1,1]) -@test !isempty(dds) -@test_throws AssertionError add_part!(dds, :X, Φ=5) -@test nparts(dds, :X) == 3 -@test subpart(dds, :Φ) == [1,1,1] -@test_throws AssertionError add_parts!(dds, :X, 2, Φ=[3,6]) -@test nparts(dds, :X) == 3 -@test incident(dds, 3, :Φ) == [] \ No newline at end of file