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

Wiring diagrams for self-dual compact closed categories #68

Merged
merged 8 commits into from
Dec 26, 2019
31 changes: 29 additions & 2 deletions docs/literate/graphics/composejl_wiring_diagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,41 @@ to_composejl((braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C)
# ### Biproduct category

A, B = Ob(FreeBiproductCategory, :A, :B)
f, g = Hom(:f, A, B), Hom(:g, B, A)
f = Hom(:f, A, B)

to_composejl(mcopy(A))
#-
to_composejl(delete(A))
#-
to_composejl(mcopy(A)⋅(f⊗f)⋅mmerge(B))

# ### Compact closed category

# The unit and co-unit of a compact closed category appear as caps and cups.

A, B = Ob(FreeBicategoryRelations, :A, :B)
f = Hom(:f, A, B)

to_composejl(dunit(A))
#-
to_composejl(dcounit(A))

# In a self-dual compact closed category, such as a bicategory of relations,
# every morphism $f: A \to B$ has a transpose $f^\dagger: B \to A$ given by
# bending wires:

to_composejl((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))

# ## Custom styles

# The visual appearance of wiring diagrams can be customized by passing Compose
# [properties](http://giovineitalia.github.io/Compose.jl/latest/gallery/properties/).

using Compose: fill, stroke

A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)
f, g = Hom(:f, A, B), Hom(:g, B, A)

to_composejl(f⋅g, box_props=[fill("lavender"), stroke("black")])

# ## Output formats
Expand All @@ -84,4 +104,11 @@ to_composejl(f⋅g, box_props=[fill("lavender"), stroke("black")])
using Compose: draw, PGF

pic = to_composejl(f⋅g, rounded_boxes=false)
draw(PGF(stdout, pic.width, pic.height), pic.context)
pgf = sprint() do io
pgf_backend = PGF(io, pic.width, pic.height,
false, # emit_on_finish
true, # only_tikz
texfonts=true)
draw(pgf_backend, pic.context)
end
println(pgf)
1 change: 1 addition & 0 deletions docs/src/apis/wiring_diagrams.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CurrentModule = Catlab.WiringDiagrams
Modules = [
WiringDiagramCore,
WiringLayers,
AlgebraicWiringDiagrams,
WiringDiagramAlgorithms,
WiringDiagramSerialization,
GraphMLWiringDiagrams,
Expand Down
7 changes: 4 additions & 3 deletions src/graphics/ComposeWiringDiagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const C = Compose

using ...WiringDiagrams
using ..WiringDiagramLayouts
using ..WiringDiagramLayouts: AbstractVector2D, Vector2D, BoxShape,
RectangleShape, JunctionShape, position, size, lower_corner, upper_corner,
normal, tangent, wire_points
using ..WiringDiagramLayouts: AbstractVector2D, Vector2D,
BoxShape, RectangleShape, JunctionShape, NoShape,
position, size, lower_corner, upper_corner, normal, tangent, wire_points

# Data types
############
Expand Down Expand Up @@ -141,6 +141,7 @@ end
function render_box(::Val{JunctionShape}, ::Any, opts::ComposeOptions)
C.compose(C.context(), C.circle(), opts.junction_props...)
end
render_box(::Val{NoShape}, ::Any, ::ComposeOptions) = C.context()

# Compose.jl forms
##################
Expand Down
2 changes: 0 additions & 2 deletions src/graphics/TikZWiringDiagrams.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
module TikZWiringDiagrams
export to_tikz

using Match

using ...Doctrines: ObExpr, HomExpr, dom, codom, head, args, compose, id
using ...Syntax: GATExpr, show_latex
using ...WiringDiagrams
Expand Down
34 changes: 19 additions & 15 deletions src/graphics/WiringDiagramLayouts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Specific features of the shape are determined by the graphics backend. For
example, a rectangle could be rendered with or without rounded corners or even
as another, similar shape, such as a rotated isosceles trapezoid.
"""
@enum BoxShape RectangleShape CircleShape JunctionShape
@enum BoxShape RectangleShape CircleShape JunctionShape NoShape

""" Layout for box in a wiring diagram.
"""
Expand Down Expand Up @@ -151,13 +151,17 @@ layout_hom_expr(f::HomExpr{:mcopy}, opts) = layout_junction_expr(f, opts)
layout_hom_expr(f::HomExpr{:delete}, opts) = layout_junction_expr(f, opts)
layout_hom_expr(f::HomExpr{:mmerge}, opts) = layout_junction_expr(f, opts)
layout_hom_expr(f::HomExpr{:create}, opts) = layout_junction_expr(f, opts)

layout_box_expr(f::HomExpr, opts) =
layout_box(f, collect(dom(f)), collect(codom(f)), opts)
layout_junction_expr(f::HomExpr, opts) =
layout_junction(f, collect(dom(f)), collect(codom(f)), opts)
layout_wires_expr(f::HomExpr, opts) =
layout_pure_wiring(to_wiring_diagram(f), opts)
layout_hom_expr(f::HomExpr{:dunit}, opts) =
layout_junction_expr(f, opts; visible=false, pad=false)
layout_hom_expr(f::HomExpr{:dcounit}, opts) =
layout_junction_expr(f, opts; visible=false, pad=false)

layout_box_expr(f::HomExpr, opts; kw...) =
layout_box(f, collect(dom(f)), collect(codom(f)), opts; kw...)
layout_junction_expr(f::HomExpr, opts; kw...) =
layout_junction(f, collect(dom(f)), collect(codom(f)), opts; kw...)
layout_wires_expr(f::HomExpr, opts; kw...) =
layout_pure_wiring(to_wiring_diagram(f), opts; kw...)

# Diagram layout
################
Expand Down Expand Up @@ -275,12 +279,12 @@ end
""" Lay out a circular junction and its ports.
"""
function layout_junction(value::Any, inputs::Vector, outputs::Vector,
opts::LayoutOptions)
radius = opts.junction_size
opts::LayoutOptions; visible::Bool=true, pad::Bool=true)
shape, radius = visible ? (JunctionShape, opts.junction_size) : (NoShape, 0)
size = 2*SVector(radius, radius)
box = Box(BoxLayout(value=value, shape=JunctionShape, size=size),
layout_circular_ports(InputPort, inputs, radius, opts),
layout_circular_ports(OutputPort, outputs, radius, opts))
box = Box(BoxLayout(value=value, shape=shape, size=size),
layout_circular_ports(InputPort, inputs, radius, opts; pad=pad),
layout_circular_ports(OutputPort, outputs, radius, opts; pad=pad))
size_to_fit!(singleton_diagram(box), opts)
end

Expand Down Expand Up @@ -318,10 +322,10 @@ end
""" Lay out ports along a circular arc.
"""
function layout_circular_ports(port_kind::PortKind, port_values::Vector,
radius::Real, opts::LayoutOptions)
radius::Real, opts::LayoutOptions; pad::Bool=true)
n = length(port_values)
θ1, θ2 = is_horizontal(opts.orientation) ? (π/2, -π/2) : (-π, 0)
θs = collect(range(θ1, θ2, length=n+2)[2:n+1])
θs = collect(pad ? range(θ1,θ2,length=n+2)[2:n+1] : range(θ1,θ2,length=n))
θs = port_sign(port_kind, opts.orientation) == -1 ? reverse(θs) : θs
dirs = [ SVector(cos(θ),-sin(θ)) for θ in θs ] # positive y-axis downwards
PortLayout[ PortLayout(value, radius * dir, dir)
Expand Down
Loading