Skip to content

Commit

Permalink
Merge pull request #204 from epatters/cset-bounds-check
Browse files Browse the repository at this point in the history
Bounds check before assigning C-set subpart
  • Loading branch information
epatters committed Jul 17, 2020
2 parents d1c561a + 4e024e7 commit 0f54542
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 8 deletions.
24 changes: 21 additions & 3 deletions src/categorical_algebra/CSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""
module CSets
export AbstractCSet, AbstractCSetType, CSet, CSetType,
nparts, subpart, has_subpart, incident,
nparts, has_part, subpart, has_subpart, incident,
add_part!, add_parts!, copy_parts!, set_subpart!, set_subparts!

using Compat
Expand Down Expand Up @@ -125,6 +125,17 @@ Base.empty(cset::T) where T <: CSet = T(map(eltype, cset.data))
"""
nparts(cset::CSet, type::Symbol) = cset.nparts[type]

""" Whether a C-set has a part with the given name.
"""
has_part(cset::CSet, type::Symbol) = _has_part(cset, Val(type))

@generated _has_part(cset::CSet{obs}, ::Val{type}) where {obs,type} =
type obs

has_part(cset::CSet, type::Symbol, part::Int) = 1 <= part <= nparts(cset, type)
has_part(cset::CSet, type::Symbol, part::AbstractVector{Int}) =
let n=nparts(cset, type); [ 1 <= x <= n for x in part ] end

""" Get subpart of part in C-set.
Both single and vectorized access are supported.
Expand All @@ -148,7 +159,7 @@ end
has_subpart(cset::CSet, name::Symbol) = _has_subpart(cset, Val(name))

@generated function _has_subpart(cset::T, ::Val{name}) where
{name, obs,homs,doms,codoms,data, T<: CSet{obs,homs,doms,codoms,data}}
{name, obs,homs,doms,codoms,data, T <: CSet{obs,homs,doms,codoms,data}}
name homs || name data
end

Expand Down Expand Up @@ -309,8 +320,12 @@ set_subpart!(cset::CSet, name::Symbol, new_subpart) =
@generated function _set_subpart!(cset::T, part::Int, ::Val{name}, subpart) where
{name, obs,homs,doms,codoms,data,data_doms,indexed,data_indexed,
T <: CSet{obs,homs,doms,codoms,data,data_doms,indexed,data_indexed}}
if name homs
codom = obs[codoms[findfirst(name .== homs)]]
end
if name indexed
quote
@assert 0 <= subpart <= cset.nparts.$codom
old = cset.subparts.$name[part]
cset.subparts.$name[part] = subpart
if old > 0
Expand All @@ -321,7 +336,10 @@ set_subpart!(cset::CSet, name::Symbol, new_subpart) =
end
end
elseif name homs
:(cset.subparts.$name[part] = subpart)
quote
@assert 0 <= subpart <= cset.nparts.$codom
cset.subparts.$name[part] = subpart
end
elseif name data_indexed
quote
old = cset.data.$name[part]
Expand Down
4 changes: 2 additions & 2 deletions src/categorical_algebra/Graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ edges(g::AbstractCSet) = 1:ne(g)
edges(g::AbstractCSet, src::Int, tgt::Int) =
(e for e in incident(g, src, :src) if subpart(g, e, :tgt) == tgt)

has_vertex(g::AbstractCSet, v::Int) = 1 <= v <= nv(g)
has_edge(g::AbstractCSet, e::Int) = 1 <= e <= ne(g)
has_vertex(g::AbstractCSet, v) = has_part(g, :V, v)
has_edge(g::AbstractCSet, e) = has_part(g, :E, e)
has_edge(g::AbstractCSet, src::Int, tgt::Int) = tgt outneighbors(g, src)

add_vertex!(g::AbstractGraph) = add_part!(g, :V)
Expand Down
17 changes: 14 additions & 3 deletions test/categorical_algebra/CSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,21 @@ set_subpart!(dds, 1, :Φ, 1)
@test subpart(dds, [2,3], ) == [1,1]
@test incident(dds, 1, ) == [1,2,3]

@test has_part(dds, :X)
@test !has_part(dds, :nonpart)
@test has_part(dds, :X, 3)
@test !has_part(dds, :X, 4)
@test has_part(dds, :X, 1:5) == [true, true, true, false, false]

@test has_subpart(dds, )
@test !has_subpart(dds, :badname)
@test_throws KeyError subpart(dds, 1, :badname)
@test_throws KeyError set_subpart!(dds, 1, :badname, 1)
@test !has_subpart(dds, :nonsubpart)
@test_throws KeyError subpart(dds, 1, :nonsubpart)
@test_throws KeyError set_subpart!(dds, 1, :nonsubpart, 1)

# Error handling
@test_throws AssertionError add_part!(dds, :X, Φ=5)
@test subpart(dds, ) == [1,1,1,0]
@test incident(dds, 4, ) == []

# Dendrograms
#############
Expand Down

0 comments on commit 0f54542

Please sign in to comment.