Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Categories of matrices #178

Merged
merged 15 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libiconv_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "e5256a3b0ebc710dbd6da0c0b212164a3681037f"
git-tree-sha1 = "a06937d9aa48855f52484c9a77a2670158fa90e2"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.0+2"
version = "1.16.0+4"

[[LightGraphs]]
deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"]
Expand Down Expand Up @@ -285,12 +285,12 @@ uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[XML2_jll]]
deps = ["Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "987c02a43fa10a491a5f0f7c46a6d3559ed6a8e2"
git-tree-sha1 = "6b2ffe6728bdba991da4fc1aa5980a53db46a23f"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.9+4"
version = "2.9.9+5"

[[Zlib_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "2f6c3e15e20e036ee0a0965879b31442b7ec50fa"
git-tree-sha1 = "33d31d2b2a24d2fdbc60633b68229ee462811c8b"
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
version = "1.2.11+9"
version = "1.2.11+13"
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
9 changes: 4 additions & 5 deletions docs/literate/graphics/composejl_wiring_diagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,15 @@ to_composejl((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dco
# ### Abelian bicategory of relations

# In an abelian bicategory of relations, such as the category of linear
# relations, the duplication morphisms $\Delta_X: X \to X \otimes X$ and
# addition morphisms $\blacktriangledown_X: X \otimes X \to X$ belong to a
# bimonoid. Among other things, this means that the following two morphisms are
# equal.
# relations, the duplication morphisms $\Delta_X: X \to X \oplus X$ and addition
# morphisms $\blacktriangledown_X: X \oplus X \to X$ belong to a bimonoid. Among
# other things, this means that the following two morphisms are equal.

X = Ob(FreeAbelianBicategoryRelations, :X)

to_composejl(plus(X) ⋅ mcopy(X))
#-
to_composejl((mcopy(X)mcopy(X)) ⋅ (id(X)⊗braid(X,X)id(X)) ⋅ (plus(X)plus(X)))
to_composejl((mcopy(X)mcopy(X)) ⋅ (id(X)⊕swap(X,X)id(X)) ⋅ (plus(X)plus(X)))

# ## Custom styles

Expand Down
9 changes: 4 additions & 5 deletions docs/literate/graphics/tikz_wiring_diagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,15 @@ to_tikz((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(
# ### Abelian bicategory of relations

# In an abelian bicategory of relations, such as the category of linear
# relations, the duplication morphisms $\Delta_X: X \to X \otimes X$ and
# addition morphisms $\blacktriangledown_X: X \otimes X \to X$ belong to a
# bimonoid. Among other things, this means that the following two morphisms are
# equal.
# relations, the duplication morphisms $\Delta_X: X \to X \oplus X$ and addition
# morphisms $\blacktriangledown_X: X \oplus X \to X$ belong to a bimonoid. Among
# other things, this means that the following two morphisms are equal.

X = Ob(FreeAbelianBicategoryRelations, :X)

to_tikz(plus(X) ⋅ mcopy(X))
#-
to_tikz((mcopy(X)mcopy(X)) ⋅ (id(X)⊗braid(X,X)id(X)) ⋅ (plus(X)plus(X)))
to_composejl((mcopy(X)mcopy(X)) ⋅ (id(X)⊕swap(X,X)id(X)) ⋅ (plus(X)plus(X)))

# ## Custom styles

Expand Down
2 changes: 2 additions & 0 deletions src/categorical_algebra/CategoricalAlgebra.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module CategoricalAlgebra

include("ShapeDiagrams.jl")
include("Matrices.jl")
include("FinSets.jl")
include("FinRelations.jl")
include("Permutations.jl")

end
28 changes: 28 additions & 0 deletions src/categorical_algebra/FinRelations.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
""" Computing in the category of finite sets and relations, and its skeleton.
"""
module FinRelations
export BoolRig, RelationMatrix

import Base: +, *, zero, one
using AutoHashEquals

using ..Matrices

""" The rig of booleans.

This struct is needed because in base Julia, the product of booleans is another
boolean, but a sum of booleans is coerced to an integer: `true + true == 2`.
"""
@auto_hash_equals struct BoolRig
epatters marked this conversation as resolved.
Show resolved Hide resolved
value::Bool
end
+(x::BoolRig, y::BoolRig) = x.value || y.value
*(x::BoolRig, y::BoolRig) = x.value && y.value
zero(::Type{BoolRig}) = false
one(::Type{BoolRig}) = true

""" A relation matrix, also known as a boolean matrix or logical matrix.
"""
const RelationMatrix = AbstractMatrix{BoolRig}

end
4 changes: 3 additions & 1 deletion src/categorical_algebra/FinSets.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
""" Computing in the category of finite sets and functions, and its skeleton.
"""
module FinSets
export FinOrd, FinOrdFunction, force, terminal, product, equalizer, pullback,
initial, coproduct, coequalizer, pushout
Expand All @@ -7,9 +9,9 @@ using DataStructures: IntDisjointSets, union!, find_root

using ...GAT
using ...Theories: Category
using ..ShapeDiagrams
import ...Theories: dom, codom, id, compose, ⋅, ∘,
terminal, product, equalizer, initial, coproduct, coequalizer
using ..ShapeDiagrams

# Data types
############
Expand Down
110 changes: 110 additions & 0 deletions src/categorical_algebra/Matrices.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
""" Categories of matrices.
"""
module Matrices
export MatrixDom, dom, codom, id, compose, ⋅, ∘,
otimes, ⊗, munit, braid, oplus, ⊕, mzero, swap,
mcopy, Δ, delete, ◊, plus, zero, pair, copair, proj1, proj2, coproj1, coproj2

import Base: +, *, zero, one
using LinearAlgebra: I
using SparseArrays
import SparseArrays: blockdiag

using ...GAT
using ...Theories: DistributiveSemiadditiveCategory
import ...Theories: dom, codom, id, compose, ⋅, ∘,
otimes, ⊗, munit, braid, oplus, ⊕, mzero, swap,
mcopy, Δ, delete, ◊, plus, zero, pair, copair, proj1, proj2, coproj1, coproj2

# Matrices over a commutative rig
#################################

""" Domain or codomain of a Julia matrix of a specific type.

Object in the category of matrices of this type.
"""
struct MatrixDom{M <: AbstractMatrix}
dim::Int
end

+(m::MD, n::MD) where MD <: MatrixDom = MD(m.dim + n.dim)
*(m::MD, n::MD) where MD <: MatrixDom = MD(m.dim * n.dim)
zero(::Type{MD}) where MD <: MatrixDom = MD(0)
one(::Type{MD}) where MD <: MatrixDom = MD(1)

""" Biproduct category of Julia matrices of specific type.

The matrices can be dense or sparse, and the element type can be any
[commutative rig](https://ncatlab.org/nlab/show/rig) (commutative semiring): any
Julia type implementing `+`, `*`, `zero`, `one` and obeying the axioms. Note
that commutativity is required only in order to define `braid`.

For a similar design (only for sparse matrices) by the Julia core developers,
see [SemiringAlgebra.jl](https://github.com/JuliaComputing/SemiringAlgebra.jl)
and [accompanying short paper](https://doi.org/10.1109/HPEC.2013.6670347).
"""
@instance DistributiveSemiadditiveCategory(MatrixDom, AbstractMatrix) begin
# FIXME: Cannot define type-parameterized instances.
#@instance AdditiveBiproductCategory(MatrixDom{M}, M) where M <: AbstractMatrix begin
@import +, dom, codom, id, mzero, munit, braid

compose(A::AbstractMatrix, B::AbstractMatrix) = B*A
plus(A::AbstractMatrix, B::AbstractMatrix) = A+B

oplus(m::MatrixDom, n::MatrixDom) = m+n
oplus(A::AbstractMatrix, B::AbstractMatrix) = blockdiag(A, B)
swap(m::MatrixDom, n::MatrixDom) = [zero(n,m) id(n); id(m) zero(m,n)]

otimes(m::MatrixDom, n::MatrixDom) = m*n
otimes(A::AbstractMatrix, B::AbstractMatrix) = kron(A, B)

mcopy(m::MatrixDom) = pair(id(m), id(m))
delete(m::MatrixDom) = zero(zero(typeof(m)), m)
plus(m::MatrixDom) = copair(id(m), id(m))
zero(m::MatrixDom) = zero(m, zero(typeof(m)))

pair(A::AbstractMatrix, B::AbstractMatrix) = [A; B]
copair(A::AbstractMatrix, B::AbstractMatrix) = [A B]
proj1(m::MatrixDom, n::MatrixDom) = [id(m) zero(m,n)]
proj2(m::MatrixDom, n::MatrixDom) = [zero(n,m) id(n)]
coproj1(m::MatrixDom, n::MatrixDom) = [id(m); zero(n,m)]
coproj2(m::MatrixDom, n::MatrixDom) = [zero(m,n); id(n)]
end

dom(A::M) where M <: AbstractMatrix = MatrixDom{M}(size(A,2))
codom(A::M) where M <: AbstractMatrix = MatrixDom{M}(size(A,1))

id(m::MatrixDom{M}) where M = M(I, m.dim, m.dim)
mzero(::Type{MD}) where MD <: MatrixDom = MD(0)
munit(::Type{MD}) where MD <: MatrixDom = MD(1)
braid(m::MatrixDom{M}, n::MatrixDom{M}) where M =
vec_permutation_matrix(M, m.dim, n.dim)
zero(m::MatrixDom{M}, n::MatrixDom{M}) where M = zero_matrix(M, m.dim, n.dim)

# Matrix utilities
##################

# Block diagonal only implemented for sparse matrices.
blockdiag(A::AbstractMatrix...) = cat(A..., dims=(1,2))

# Dense and sparse matrices have different APIs for creating zero matrices.
zero_matrix(::Type{<:AbstractMatrix{T}}, dims...) where T = zeros(T, dims...)
zero_matrix(::Type{SparseMatrixCSC{T}}, dims...) where T = spzeros(T, dims...)

function unit_vector(::Type{M}, n::Int, i::Int) where {T, M <: AbstractMatrix{T}}
x = zero_matrix(M, n, 1)
x[i,1] = one(T)
x
end

""" The "vec-permutation" matrix, aka the "perfect shuffle" permutation matrix.

This formula is (Henderson & Searle, 1981, "The vec-permutation matrix, the vec
operator and Kronecker products: a review", Equation 18). Many other formulas
are given there.
"""
function vec_permutation_matrix(::Type{M}, m::Int, n::Int) where M <: AbstractMatrix
hcat((kron(M(I, n, n), unit_vector(M, m, j)) for j in 1:m)...)
epatters marked this conversation as resolved.
Show resolved Hide resolved
end

end
5 changes: 3 additions & 2 deletions src/graphics/WiringDiagramLayouts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,12 @@ layout_hom_expr(f::HomExpr, opts) = layout_box(f, opts)

layout_hom_expr(f::HomExpr{:compose}, opts) =
compose_with_layout!(map(arg -> layout_hom_expr(arg, opts), args(f)), opts)
layout_hom_expr(f::HomExpr{:otimes}, opts) =
layout_hom_expr(f::Union{HomExpr{:otimes},HomExpr{:oplus}}, opts) =
otimes_with_layout!(map(arg -> layout_hom_expr(arg, opts), args(f)), opts)

layout_hom_expr(f::HomExpr{:id}, opts) = layout_pure_wiring(f, opts)
layout_hom_expr(f::HomExpr{:braid}, opts) = layout_pure_wiring(f, opts)
layout_hom_expr(f::Union{HomExpr{:braid},HomExpr{:swap}}, opts) =
layout_pure_wiring(f, opts)

layout_hom_expr(f::HomExpr{:mcopy}, opts) = layout_supply(f, opts, shape=:junction)
layout_hom_expr(f::HomExpr{:delete}, opts) = layout_supply(f, opts, shape=:junction)
Expand Down
Loading