@@ -4,7 +4,7 @@ module FinSets
44export FinSet, FinFunction, FinDomFunction, TabularSet, TabularLimit,
55 force, is_indexed, preimage, VarFunction, LooseVarFunction,
66 JoinAlgorithm, SmartJoin, NestedLoopJoin, SortMergeJoin, HashJoin,
7- SubFinSet, SubOpBoolean, is_monic, is_epic
7+ SubFinSet, SubOpBoolean, is_monic, is_epic, FinBijection
88
99using StructEquality
1010using DataStructures: OrderedDict, IntDisjointSets, union!, find_root!
@@ -25,7 +25,8 @@ import ..FinCats: force, ob_generators, hom_generators, ob_generator,
2525using .. FinCats: dicttype
2626import .. Limits: limit, colimit, universal, BipartiteColimit
2727import .. Subobjects: Subobject
28- using .. Sets: IdentityFunction, SetFunctionCallable
28+ using .. Sets: IdentityFunction, SetFunctionCallable, AbsBijectionWrap,
29+ BijectionBimap, BijectionThinWrap, unwrap
2930
3031# Finite sets
3132# ############
@@ -459,12 +460,16 @@ is_indexed(f::SetFunction) = false
459460is_indexed (f:: IdentityFunction ) = true
460461is_indexed (f:: IndexedFinDomFunctionVector ) = true
461462is_indexed (f:: FinDomFunctionVector{T,<:AbstractRange{T}} ) where T = true
463+ is_indexed (f:: BijectionThinWrap ) = is_indexed (f. func)
464+ is_indexed (f:: BijectionBimap ) = true
462465
463466""" The preimage (inverse image) of the value y in the codomain.
464467"""
465468preimage (f:: IdentityFunction , y) = SVector (y)
466469preimage (f:: FinDomFunction , y) = [ x for x in dom (f) if f (x) == y ]
467470preimage (f:: IndexedFinDomFunctionVector , y) = get_preimage_index (f. index, y)
471+ preimage (f:: BijectionThinWrap , y) = preimage (unwrap (f), y)
472+ preimage (f:: BijectionBimap , y) = f. inv (y)
468473
469474@inline get_preimage_index (index:: AbstractDict , y) = get (index, y, 1 : 0 )
470475@inline get_preimage_index (index:: AbstractVector , y) = index[y]
@@ -571,6 +576,166 @@ Sets.do_compose(f::FinFunctionDict{K,D}, g::FinDomFunctionDict) where {K,D} =
571576 FinDomFunctionDict (dicttype (D)(x => g. func[y] for (x,y) in pairs (f. func)),
572577 codom (g))
573578
579+ # Category of finite sets and bijections
580+ # #######################################
581+
582+ """ Bijection between finite sets.
583+ """
584+ const FinBijection{S, S′, Dom <: FinSet{S} , Codom <: FinSet{S′} } =
585+ Bijection{Dom, Codom}
586+
587+ FinBijection (f, args... ) = FinBijection (f, (FinSet (a) for a in args). .. )
588+ FinBijection (f:: Function , dom:: FinSet , codom:: FinSet ) =
589+ BijectionThinWrap (SetFunction (f, dom, codom))
590+ FinBijection (f:: FinFunction ) = BijectionThinWrap (f)
591+ FinBijection (f:: FinFunction , g:: FinFunction ) = BijectionBimap (unwrap (f), unwrap (g))
592+ FinBijection (f:: AbstractVector ) =
593+ BijectionThinWrap (FinDomFunction (f, FinSet (Set (f))))
594+ FinBijection (f:: AbstractVector , a, args... ) =
595+ BijectionThinWrap (FinDomFunction (f, FinSet (a), args... ))
596+ FinBijection (f:: AbstractDict , args... ) =
597+ BijectionThinWrap (FinFunction (f, args... ))
598+
599+ function FinBijection (f:: Union{AbstractDict{K,Int},AbstractVector{Int}} ) where K
600+ function minandmax (p:: Tuple{<:Number, <:Number} , n:: Int ):: Tuple{Int,Int}
601+ (Int (min (p[1 ], n)), Int (max (p[2 ], n)))
602+ end
603+ minval, maxval = reduce (minandmax, values (f), init= (Inf , - Inf ))
604+ len = length (f)
605+ cod = minval == 1 && maxval == len ? FinSet (len) : Set (v)
606+ BijectionThinWrap (FinFunction (f, cod))
607+ end
608+
609+ Sets. show_type_constructor (io:: IO , :: Type{<:FinBijection} ) =
610+ print (io, " FinBijection" )
611+
612+ """ Abstract (alias) type for bijections on finite sets which are implemented
613+ by wrapping another `FinFunction` object.
614+ """
615+ const FinBijectionWrap{S,S′,Dom<: FinSet{S} ,Codom<: FinSet{S′} ,
616+ F<: FinFunction{S,S′,Dom,Codom} } = AbsBijectionWrap{Dom, Codom, F}
617+
618+ force (f:: FinBijectionWrap ) = FinBijection (force (unwrap (f)))
619+
620+ """ Alias for all `FinBijection`s that wrap `Vector`s.
621+ """
622+ const FinBijectionVector = Union{
623+ AbsBijectionWrap{
624+ FinSetInt, Codom, FinFunctionVector{S,T,V,Codom}
625+ } where {S, T, V<: AbstractVector{T} , Codom<: FinSet{S,T} },
626+ AbsBijectionWrap{
627+ FinSetInt, FinSetInt, IndexedFinFunctionVector{V,Index}
628+ } where {V<: AbstractVector{Int} , Index},
629+ }
630+
631+ force (f:: FinBijectionVector ) = f
632+
633+ Sets. do_compose (f:: FinBijectionVector , g:: FinBijectionVector ) =
634+ BijectionThinWrap (Sets. do_compose (unwrap (f), unwrap (g)))
635+
636+ """ Alias for all `FinBijection`s that wrap `Dict`s.
637+ """
638+ const FinBijectionDict{K,D<: AbstractDict{K} ,S,Codom<: FinSet{S} } =
639+ AbsBijectionWrap{
640+ FinSetCollection{Base. KeySet{K,D}}, Codom, FinFunctionDict{K,D,S,Codom}
641+ } where {K, D<: AbstractDict{K} , S, Codom<: FinSet{S} }
642+
643+ force (f:: FinBijectionDict ) = f
644+
645+ Sets. do_compose (f:: FinBijectionDict , g:: FinBijectionDict ) =
646+ BijectionThinWrap (Sets. do_compose (unwrap (f), unwrap (g)))
647+
648+ function Sets. do_inv (f:: FinBijection{S,S′,Dom,Codom} ) where
649+ {S,S′,T,T′,Dom<: FinSet{S,T} ,Codom<: FinSet{S′,T′} }
650+ domain, cod = dom (f), codom (f)
651+ func = S′ == Int ? Vector {T} (undef, length (cod)) : Dict {T′,T} ()
652+ for x in domain
653+ func[f (x)] = x
654+ end
655+ FinDomFunction (func, domain)
656+ end
657+
658+ """ Finite bijection whose form in cycle notation is known.
659+
660+ Computing a bijection's cycles from its function requires the same computations
661+ as computing the inverse. Furthermore, the inverse of a function can be computed
662+ from its cycles just as easily as the function itself. This type is designed
663+ with these facts in mind.
664+ """
665+ struct FinBijectionCycles{S,T,Dom<: FinSet{S,T} ,F<: FinFunction{S,S,Dom,Dom} ,
666+ G<: FinFunction{S,S,Dom,Dom} } <: AbsBijectionWrap{Dom,Dom,F}
667+ func:: BijectionBimap{Dom,Dom,F,G}
668+ cycles:: Vector{Vector{T}}
669+ end
670+
671+ function FinBijectionCycles (f:: FinBijection{S,S,Dom,Dom} ) where
672+ {S,T,Dom<: FinSet{S,T} }
673+ domain = dom (f)
674+ cycles = Vector{T}[]
675+ if S == Int
676+ invfunc, used = Vector {Int} (undef, length (domain)), falses (length (domain))
677+ else
678+ invfunc, used = Dict {T,T} (), Dict (k=> false for k in domain)
679+ end
680+ # Developer's note: this loop recapitulates the approach of the extant
681+ # function `Permutations.cycles`, with the difference that it ignores
682+ # trivial cycles and interleaves the computation of the inverse
683+ for i in domain
684+ if used[i]; continue end
685+ used[i] = true
686+ j = f (i)
687+ invfunc[j] = i
688+ if j != i
689+ cycle = [i]
690+ while true
691+ push! (cycle, j)
692+ used[j] = true
693+ k = j
694+ j = f (j)
695+ invfunc[j] = k
696+ if j == i; break end
697+ end
698+ push! (cycles, cycle)
699+ end
700+ end
701+ bimap = BijectionBimap (f, FinDomFunction (invfunc, dom (f)))
702+ FinBijectionCycles (bimap, cycles)
703+ end
704+
705+ function FinBijectionCycles (f:: AbstractVector{<:AbstractVector{T}} ,
706+ dom:: FinSet{S,T} ) where {S,T}
707+ domlen = length (dom)
708+ if S == Int
709+ func, invfunc = Vector {Int} (undef, domlen), Vector {Int} (undef, domlen)
710+ else
711+ func, invfunc = Dict {T,T} (), Dict {T,T} ()
712+ end
713+ lengths = map (length, f)
714+ for (i, cycle) in enumerate (f)
715+ len = lengths[i]
716+ lenmod = n -> mod (n, len)
717+ for (j, x) in enumerate (cycle)
718+ func[x], invfunc[x] = cycle[lenmod (j+ 1 )], cycle[lenmod (j- 1 )]
719+ end
720+ end
721+ bimap = FinBijection (FinDomFunction (func, dom), FinDomFunction (invfunc, dom))
722+ FinBijectionCycles (bimap, f)
723+ end
724+
725+ Base.:(== )(f:: FinBijectionCycles , g:: FinBijectionCycles ) = f. func == g. func
726+ Base. hash (f:: FinBijectionCycles ) = hash (f. func)
727+
728+ Sets. compose_inv (f:: FinBijectionCycles , g:: SetFunction ) = compose_inv (f. func, g)
729+ Sets. compose_inv (f:: SetFunction , g:: FinBijectionCycles ) = compose_inv (f, g. func)
730+ Sets. compose_inv (f:: FinBijectionCycles , g:: FinBijectionCycles ) =
731+ compose_inv (f. func, g. func)
732+
733+ Base. inv (f:: FinBijectionCycles ) =
734+ FinBijectionCycles (inv (f. func), [reverse (c) for c in f. cycles])
735+
736+ is_indexed (f:: FinBijectionCycles ) = true
737+ preimage (f:: FinBijectionCycles , y) = preimage (f. func, y)
738+
574739# Limits
575740# #######
576741
0 commit comments