Skip to content

Commit

Permalink
ENH: Functions in Set represented by dictionaries.
Browse files Browse the repository at this point in the history
  • Loading branch information
epatters committed Nov 30, 2021
1 parent b9d6aa7 commit 660d0a7
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 13 deletions.
9 changes: 6 additions & 3 deletions src/categorical_algebra/Categories.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,16 @@ end

show_type_constructor(io::IO, ::Type{<:Functor}) = print(io, "Functor")

function show_domains(io::IO, f; codomain::Bool=true, recurse::Bool=true)
function show_domains(io::IO, f; domain::Bool=true, codomain::Bool=true,
recurse::Bool=true)
if get(io, :hide_domains, false)
print(io, "")
else
show(IOContext(io, :compact=>true, :hide_domains=>!recurse), dom(f))
if domain
show(IOContext(io, :compact=>true, :hide_domains=>!recurse), dom(f))
end
if codomain
print(io, ", ")
domain && print(io, ", ")
show(IOContext(io, :compact=>true, :hide_domains=>!recurse), codom(f))
end
end
Expand Down
71 changes: 61 additions & 10 deletions src/categorical_algebra/FinSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ using ..FinCats, ..FreeDiagrams, ..Limits, ..Subobjects
import ...Theories: Ob, meet, , join, , top, ⊤, bottom, ⊥
import ..Categories: ob, hom, dom, codom, compose, id, ob_map, hom_map
import ..FinCats: force, ob_generators, hom_generators, graph, is_discrete
using ..FinCats: dicttype
import ..Limits: limit, colimit, universal, pushout_complement,
can_pushout_complement
import ..Subobjects: Subobject, SubobjectLattice
Expand Down Expand Up @@ -63,9 +64,11 @@ be, but is not required to be, set-like (a subtype of `AbstractSet`).
@auto_hash_equals struct FinSetCollection{S,T} <: FinSet{S,T}
collection::S
end
FinSetCollection(collection::S) where S =
FinSetCollection{S,eltype(collection)}(collection)

FinSet(col::S) where {T, S<:Union{AbstractVector{T},AbstractSet{T}}} =
FinSetCollection{S,T}(col)
FinSet(collection::S) where {T, S<:Union{AbstractVector{T},AbstractSet{T}}} =
FinSetCollection{S,T}(collection)

Base.iterate(set::FinSetCollection, args...) = iterate(set.collection, args...)
Base.length(set::FinSetCollection) = length(set.collection)
Expand Down Expand Up @@ -172,8 +175,8 @@ FinFunction(f::Function, dom, codom) =
SetFunctionCallable(f, FinSet(dom), FinSet(codom))
FinFunction(::typeof(identity), args...) =
IdentityFunction((FinSet(arg) for arg in args)...)
FinFunction(f::AbstractVector{Int}; kw...) =
FinDomFunctionVector(f, FinSet(isempty(f) ? 0 : maximum(f)); kw...)
FinFunction(f::AbstractDict, args...) =
FinFunctionDict(f, (FinSet(arg) for arg in args)...)

function FinFunction(f::AbstractVector{Int}, args...; index=false)
if index == false
Expand All @@ -183,6 +186,8 @@ function FinFunction(f::AbstractVector{Int}, args...; index=false)
IndexedFinFunctionVector(f, args...; index=index)
end
end
FinFunction(f::AbstractVector{Int}; kw...) =
FinFunction(f, FinSet(isempty(f) ? 0 : maximum(f)); kw...)

Sets.show_type_constructor(io::IO, ::Type{<:FinFunction}) =
print(io, "FinFunction")
Expand All @@ -198,6 +203,7 @@ FinDomFunction(f::Function, dom, codom) =
SetFunctionCallable(f, FinSet(dom), codom)
FinDomFunction(::typeof(identity), args...) =
IdentityFunction((FinSet(arg) for arg in args)...)
FinDomFunction(f::AbstractDict, args...) = FinDomFunctionDict(f, args...)

function FinDomFunction(f::AbstractVector, args...; index=false)
if index == false
Expand Down Expand Up @@ -371,6 +377,53 @@ Sets.do_compose(f::Union{FinFunctionVector,IndexedFinFunctionVector},
g::Union{FinDomFunctionVector,IndexedFinDomFunctionVector}) =
FinDomFunctionVector(g.func[f.func], codom(g))

# Dict-based functions
#---------------------

""" Function in **Set** represented by a dictionary.
The domain is a `FinSet{S}` where `S` is the type of the dictionary's `keys`
collection.
"""
@auto_hash_equals struct FinDomFunctionDict{K,D<:AbstractDict{K},Codom<:SetOb} <:
FinDomFunction{D,FinSet{AbstractSet{K},K},Codom}
func::D
codom::Codom
end

FinDomFunctionDict(d::AbstractDict{K,V}) where {K,V} =
FinDomFunctionDict(d, TypeSet{V}())

dom(f::FinDomFunctionDict) = FinSet(keys(f.func))

(f::FinDomFunctionDict)(x) = f.func[x]

function Base.show(io::IO, f::F) where F <: FinDomFunctionDict
Sets.show_type_constructor(io, F)
print(io, "(")
show(io, f.func)
print(io, ", ")
Sets.show_domains(io, f, domain=false)
print(io, ")")
end

force(f::FinDomFunction) =
FinDomFunctionDict(Dict(x => f(x) for x in dom(f)), codom(f))
force(f::FinDomFunctionDict) = f

""" Function in **FinSet** represented by a dictionary.
"""
const FinFunctionDict{K,D<:AbstractDict{K},Codom<:FinSet} =
FinDomFunctionDict{K,D,Codom}

FinFunctionDict(d::AbstractDict, codom::FinSet) = FinDomFunctionDict(d, codom)
FinFunctionDict(d::AbstractDict{K,V}) where {K,V} =
FinDomFunctionDict(d, FinSet(Set(values(d))))

Sets.do_compose(f::FinFunctionDict{K,D}, g::FinDomFunctionDict) where {K,D} =
FinDomFunctionDict(dicttype(D)(x => g.func[y] for (x,y) in pairs(f.func)),
codom(g))

# Limits
########

Expand Down Expand Up @@ -1121,12 +1174,10 @@ function id_condition(pair::ComposablePair{<:FinSet{Int}})
l_image = Set(collect(l))
l_imageᶜ = [ x for x in codom(l) if x l_image ]
m_image = Set(map(m, l_imageᶜ))
return (
(i for i in l_image if m(i) m_image),
((i, j) for i in eachindex(l_imageᶜ)
for j in i+1:length(l_imageᶜ)
if m(l_imageᶜ[i]) == m(l_imageᶜ[j]))
)
((i for i in l_image if m(i) m_image),
((i, j) for i in eachindex(l_imageᶜ)
for j in i+1:length(l_imageᶜ)
if m(l_imageᶜ[i]) == m(l_imageᶜ[j])))
end

# Subsets
Expand Down
13 changes: 13 additions & 0 deletions test/categorical_algebra/FinSets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,26 @@ h = FinFunction([3,1,2], 3)
@test force(f) === f
@test codom(FinFunction([1,3,4])) == FinSet(4)

X = FinSet(Set([:w,:x,:y,:z]))
k = FinFunction(Dict(:a => :x, :b => :y, :c => :z), X)
= FinFunction(Dict(:w => 2, :x => 1, :y => 1, :z => 4), FinSet(4))
@test (dom(k), codom(k)) == (FinSet(Set([:a, :b, :c])), X)
@test (dom(ℓ), codom(ℓ)) == (X, FinSet(4))
@test force(k) === k
@test codom(FinFunction(Dict(:a => :x, :b => :y, :c => :z))) ==
FinSet(Set([:x,:y,:z]))

# Evaluation.
rot3(x) = (x % 3) + 1
@test map(f, 1:3) == [1,3,4]
@test map(k, [:a,:b,:c]) == [:x,:y,:z]
@test map(FinFunction(rot3, 3, 3), 1:3) == [2,3,1]
@test map(id(FinSet(3)), 1:3) == [1,2,3]

# Composition.
@test compose(f,g) == FinFunction([1,2,2], 3)
@test compose(g,h) == FinFunction([3,3,1,1,2], 3)
@test compose(k,ℓ) == FinFunction(Dict(:a => 1, :b => 1, :c => 4), FinSet(4))
@test compose(compose(f,g),h) == compose(f,compose(g,h))
@test compose(id(dom(f)), f) == f
@test compose(f, id(codom(f))) == f
Expand Down Expand Up @@ -92,6 +103,8 @@ g = FinFunction(5:-1:1)
@test sshow(FinFunction([1,3,4], 5)) == "FinFunction($([1,3,4]), 3, 5)"
@test sshow(FinFunction([1,3,4], 5, index=true)) ==
"FinFunction($([1,3,4]), 3, 5, index=true)"
@test sshow(FinFunction(Dict(:a => 1, :b => 3), FinSet(3))) ==
"FinFunction($(Dict(:a => 1, :b => 3)), FinSet(3))"

# Functions out of finite sets
##############################
Expand Down

0 comments on commit 660d0a7

Please sign in to comment.